This guide is copied from the published preview tag. See the night-to-morning experience →
co rem — current branch contract
Updated 2026-09-24. co rem ships in the opt-in 1.8.8 previews and becomes
long-term supported in 1.9.0 (#1664 names it first). The command surface and
every --help page are the agreed design in #1656; the pages themselves live
in connectonion/cli/commands/rem_help.md and a test holds them to the code.
Old command names (unfinished, people, daily, subscribe, subscriptions,
unsubscribe, route, usage) still work until 1.9.0 and print their new name.
See the 2026-09-17 progress review for the feature inventory, current CI blockers and remaining work.
Coming from co wiki (1.8.8–1.8.9)
1.9.0 renames the feature co rem (#1932). Nothing needs doing by hand:
- The first
co remmoves~/.co/wikito~/.co/remand says so in one line. If both folders exist it refuses, names both, and merges nothing. An explicit--rootis used as given. A move that fails leaves the old folder whole. - A daily schedule that
co wiki startinstalled is replaced by one that runsco rem sync, the next timeco remruns for that notebook. co wiki …runs nothing in 1.9.x: it exits 2 withco wiki is now co rem.and oneNext: co rem …line with the same arguments. It is removed in 1.10.CO_WIKI_PROGRAMis still read whenCO_REM_PROGRAMis not set, with a one-line notice.pip install 'connectonion[wiki]'still installs the spreadsheet extra, now calledrem.
Start here
co rem init # Build the map (no model), show your own page, then write it (one model turn)
co rem open # Read your page
co rem start # Keep it current: approve sources, turn on the daily round
The first run is one command (#1943). init is a script: it maps 90 days of
mail and your local Codex / Claude Code sessions, saves the private mail
material, and prints your own page's facts — who you write to most, how much
mail, which projects you have been coding in — with the page's path, within the
first minutes. Then, in a terminal, it writes your own page by itself: the whole
investigate me, from everything you sent and your coding sessions of the last
30 days (or --days), one model turn over evidence files, about 15 minutes.
Next come the 3 people you wrote to most in the last 14 days, one turn each,
reading the run's own --days of their mail (not the 150 days a full
investigation reads), and then your 3 most recently active projects, from the
messages you typed in their Codex and Claude Code sessions (the
co rem projects write pass, #1947). --first-people N and
--first-projects N change the counts (0 for none).
Before it spends anything it says one total (#2008): which runner and model,
that it runs on your own plan, and "About N pages (...), X billed input tokens,
~Y minutes (an estimate ...)". Per page it is the median of this notebook's own
completed runs of that kind (90k
and about a minute" per project and wrote every project active in the window.
The whole first run stops starting pages once it has used 5 points of the Codex
week (half the notebook's weekly 10), or at the weekly floor. Ctrl-C stops it,
says which pages were written, keeps the map and every page, and names the
command that continues. It skips the model steps, with a one-line reason, when
the runner is not installed or not signed in (checked before the map starts,
without a model), when no mailbox gave an address of yours, when your page was
already written, or when there is no terminal (scripts and .state/runs/); before there are any, the
defaults measured on the owner's real notebook on 2026-10-01: your page 680k and
~6 minutes (measured 678k, 6m17s), a person 425k and ~5 minutes (150k–700k), a
project 750k and ~4.5 minutes (614k and 922k, 4–5 minutes). 1.9.0a5 said "--json) unless
--investigate is given. --no-investigate builds the map only. Older
projects wait for co rem projects write; more people for
co rem investigate people.
Your page is titled with what you are called: --name if given, else the
name the people writing to you put on your address (the To and Cc of mail you
received; spellings that differ only in case are one name, and a name that is
just the address, xietianle, is not one), else the From name of mail you
sent, else the name a mailbox has configured (#2008). On the owner's real
account the configured name was "Aaron x", and Outlook stamps it on every sent
mail too; correspondents wrote "Aaron Xie". A new notebook names the file after
you (people/aaron-xie-….md); an existing page keeps its path.
Progress is one line per stage (updated in place in a terminal); every step is
kept in .state/init-progress.log. Addresses that look like yours (you wrote,
nobody replied) are listed on one line with one command that confirms the ones
you keep: co rem init --mine a@example.org,b@example.org. Mailboxes init read
are subscribed, so co rem start's summary lists them as sources to read; start
still asks before anything is read in the background.
To fill other pages, co rem investigate lists what is left, by category, and
runs no model. Copy the Next: command printed by investigate to investigate one existing
page. You can also supply an exact title or email when it identifies one page,
for example co rem investigate 'Ody' if that person exists in your notebook.
Ambiguous names list the matching paths and do not start a model. Example page
names in old help text, such as people/emma.md, are not built-in records.
--help displays help and exits, even when you also supply a page name.
co rem investigate # What is left to investigate, by category; no model
co rem investigate me --quick --days 5 # Bounded first pass; disclose uncovered sources
co rem open # Open a fresh snapshot of the notebook in your browser
co rem sync --dry-run # Inspect pending metadata, without running a model
co rem sync # One update: new material, then at most one unfinished page
co rem logs # Inspect results, partial coverage and failures
Normal output uses readable labels and plain page paths. Empty lists explain
what is missing; unknown usage remains Unknown, never zero. Results end
with a copyable Next: command, including the selected root and shell quoting.
Use co rem --help as the workflow guide: it gives task selection,
observed inputs, expected results, source/quality checks and recovery before
the command inventory. init --help, investigate --help and sync --help
explain their full workflow as well as options. The overview and group help
share one implementation, so human and agent guidance cannot drift separately. Root and JSON flags belong before the subcommand:
co rem --root '/path/to/my co rem' investigate
co rem --root '/path/to/my co rem' --json status
Explicit --json retains the ok, data, and next envelope for scripts.
No-argument --json continues to return status, without the human guide.
Piping human output does not hide the next step. Grouped help covers:
| Task | Commands |
|---|---|
| Map and investigate | init, investigate, map-skills, scan, stub |
| Browse | open, list, show, search, status |
| Update and review | sync, capture, reflect, reflections, propose, review, abstract |
| Sources and background | sources, sources add, sources remove, start, stop |
| Settings and diagnostics | config, config set, logs, doctor |
start explicitly authorizes collection and installs background maintenance
plus at most one unfinished-page investigation per local day when the day's
call budget allows;
init does neither. A mapped page is not an investigated or quality-approved page.
For an initial trial, co rem init --days 5 investigates your page over the same
five-day window. investigate me --quick is the older bounded pass: it samples
recent evidence, takes one synthesis turn, and marks its coverage as partial.
init no longer uses it, since #1850's evidence files let one turn search
everything you sent.
Installed-skill skeletons at initialization
co rem init deterministically builds People, Organizations, Projects and Skills pages from
their canonical templates and available source metadata before any model
investigation. Unknown fields remain explicit; investigation is a separate step.
See the initialization interaction contract.
Its coverage lines keep the four source states apart, because each one needs a different next command:
gmail: metadata only, 90 days; a seven-day window at the 200-message listing cap is split until every message in it is listed; 42 correspondents
outlook: not connected; not searched. Connect it with co auth microsoft
codex: /home/you/.codex/sessions — scanned; no sessions in this window
claude-code: /home/you/.claude/projects — disabled; not scanned
A mailbox that was read and held nobody, one nobody has connected, one the user unsubscribed, and one that is connected but would not open are four different answers; so are a session directory that is missing, one switched off, and one scanned that had nothing inside the window.
Where init can see that an address is probably the user's own — mail goes to it
repeatedly and nothing ever comes back — it says so and prints the exact
init --mine <address> that confirms it. It never merges on the guess: an
assistant and a family member look the same from the headers.
The map can also be run independently:
co rem --root /private/path/to/rem map-skills
co rem --root /private/path/to/rem map-skills --skills-dir /known/project/.co/skills
The generated skills/catalog/index.md links to one page per skill name
(#1974). A skill installed three times — in ~/.claude/skills, ~/.codex/skills
and ~/.agents/skills — is one page, not three. The page links to the source
file instead of pasting it, and keeps the frontmatter facts short: the name, the
description, the allowed tools. Its Source section, which the map owns and
rewrites on every run, lists each copy:
## Source
- File: /home/you/.claude/skills/ship-feature/SKILL.md
- Discovery: claude-user
- Allowed tools: Bash, Read
- Content: sha256 3f2a9c1e04b7; 3 installed copies
- Also installed at: /home/you/.codex/skills/ship-feature/SKILL.md (identical)
- Also installed at: /home/you/.agents/skills/ship-feature/SKILL.md (differs: sha256 77b0d2e41f9a)
- Status: mapped from metadata; behavior not verified
Copies are compared by content hash, so a copy that has drifted says so. A copy
in a temporary or package location — a git worktree (.claude/worktrees/,
.worktree/, .worktrees/, .codex/worktrees/), site-packages, a plugin
cache — never becomes the File of a page and never
makes a page of its own; it is listed as Also installed at on the page of a
copy that lives somewhere real. A name found only in such places is listed in
the index under "Only in temporary or package locations", without a page.
Usage history opens with what your own coding sessions say, counted by a
script with no model: how many times the skill was invoked and when last.
- Invoked 14 times in your coding sessions in the last 180 days, last on 2026-09-28 (Claude Code 9, Codex 5). ...
Claude Code counts a Skill tool call and a /skill-name command; Codex counts
a $skill-name in a message you typed (read as sync reads it, Codex Desktop
included) and a tool call that reads the skill's
SKILL.md, once per turn. co rem's own runs are not counted. An invocation is
not a completed run: Current status and Performance still wait for run
evidence. Counts are cached per session file under .state/skill-usage.json,
so a rerun reads only what changed.
Rerunning the map (init, sync's map, or map-skills) moves an older
notebook to this shape. Pages made one per copy are merged into the name's page:
a page with written content keeps it (sections are merged line by line, citations
renumbered), the pasted SKILL.md snapshot is removed, and the old page is
moved to .state/archived/ — never deleted. Its record becomes an alias
(.state/aliases.json): links to it in other pages are rewritten, and a command
given the old name opens the merged page. A page whose only source was a
temporary copy and that holds nothing but map output is archived the same way.
Original SKILL.md files are never changed or run, and skills/approved/
remains write-protected.
Defaults cover the co/Claude skill search roots, conventional agent/Codex skill
roots, and co ai's bundled default allowlist. This is a shallow inventory, not
an exhaustive plugin-cache or remote-catalog scan. Repeat --skills-dir for
explicit roots; supplying it replaces defaults for that scan. Coverage and
unreadable files are reported in the index and command result.
The co rem CLI reference explains mail IDs, browser tabs, source/working/output directories and failure recovery.
One execution path
User / scheduler
|
v
co rem init / investigate / sync / abstract
|
| stage Skill + source Skill + page shape + material paths
v
co ai --json --harness <codex | claude-code | ours> /rem-<stage>
|
+-- Codex tool --> Codex subscription
+-- Claude Code tool --> Claude Code subscription
+-- COAI agent --> configured LLM provider (including Ollama)
|
v
Markdown pages + reported usage + observed file changes
COAI already delegates before creating its own LLM loop. Selecting Codex therefore does not spend a COAI model turn deciding to delegate. All co rem stages, including extraction and maintenance, use that same command.
co rem's former app-server subclass, dynamic rem_* tools, isolated Codex HOME, auth-file copying, native version/config checks and direct native extraction path have been removed. The shared COAI native adapters remain: their job is to speak Codex or Claude Code's protocol once for all callers.
co rem retains source importers, bounded digest batches, page templates, identity roster, progress, sync locking/accounting, OS scheduling and the reader. A shell can call the public CLI; rewriting these data operations as a second shell implementation would duplicate behavior.
Commands
Group options precede the command: co rem --root /path/to/rem --json list.
Every command returns a next command, including in JSON and through a pipe.
| Command | Behavior |
|---|---|
co rem init |
Discover accounts and local sources, build People/Organizations/Projects/Skills pages with no model, print your own page's facts, then (in a terminal) write your own page with one model turn. --no-investigate stops after the map. |
co rem scan people --days 150 --min-mails 1 |
Enumerate correspondent signals from Gmail/Outlook; no model. Repeat --mine <address> for own addresses. |
co rem scan orgs --days 180 --min-people 2 |
List work domains that two or more people write from — where an organisation page earns its place. No model. |
co rem scan projects --days 150 |
Enumerate session working directories and local Git repository identities; no model. |
co rem stub person "Alice" --email alice@example.org --handle 艾丽丝 |
Create the canonical person skeleton if absent. |
co rem stub org "UNSW" --domain unsw.edu.au --person people/vern-chan.md |
Create an organisation skeleton; People here holds links, not copies. |
co rem stub project "Aurora" --path /path/to/repo |
Create a project skeleton. |
co rem list people --aliases |
Existing identity roster: page, title, aliases, addresses, relationship summary. |
co rem list people --review |
Pages held for review: titled by an address the owner never wrote to, or only ever wrote to. |
co rem investigate people/alice.md |
Read the existing page, gather sources, digest oversized material, fill that same page through the Skill. |
co rem investigate |
What is left to investigate, by category, most useful first. No model. |
co rem investigate people --limit 3 |
Investigate the next three people, the last 14 days' correspondents first (--recent-days): a person investigated before reads only the mail since then (details). --list prints the order and the cost and runs nothing. projects, orgs, skills take unfinished pages, most mail or sessions first. |
co rem investigate me |
Fill your own page from what you sent and your coding sessions of the last 30 days. |
co rem abstract |
Run rem-abstract over existing notebook evidence. |
co rem start |
Confirm source access, run first bounded sync, install macOS background schedule. Asks again whenever anything its summary shows (sources, runner, model, permissions, schedule, limits) changed since the last approval. A start after stop resumes the schedule without a batch; co rem sync runs one. |
co rem start --yes |
Explicit noninteractive consent for start. |
co rem stop |
Remove that notebook's background job; preserve pages and progress. |
co rem sync |
The whole update: one batch of new material; then the day's first run investigates unfinished pages, most recent first, and every later run updates only the people and projects with something new. What the schedule runs (sync --scheduled). |
co rem sync --source codex --dry-run |
Pending metadata only; no model or source body reads. |
co rem sources add codex --project /path/to/repo --since 30d |
Save a scoped source choice. |
co rem sources add whatsapp --chat <id> |
Read one WhatsApp chat (group or person) from the files co whatsapp listen keeps; ids from co whatsapp chats. Repeat per chat; the next co rem start shows it and asks before anything is read. co rem sources remove whatsapp --chat <id> stops one chat. |
co rem sources remove codex |
Disable that source. |
co rem list people / show people/alice.md / search Alice |
Inspect Markdown without model calls. |
co rem status / sources / config / logs / logs --usage / doctor |
Inspect configuration, progress, diagnostics and reported usage. |
co rem open |
Render a fresh self-contained HTML snapshot to a temporary file and open it. Works offline; prints the file path and a file:// link. |
co rem open --live |
Open the live view in O Chat, read from your co ai Host over OIP. Checks first that the Host is online; if it is not, says so (start it with co ai) and opens the snapshot instead. Default notebook only. |
co rem open --no-launch |
Print the page without opening the browser. |
Until 1.8.9 the default opened https://chat.openonion.ai/<address>/wiki before
O Chat served that route, so the page never loaded (#1828). O Chat serves it
since openonion/oo-chat#246; opening locally stays the default because it works
offline and needs no Host, and the live view is asked for with --live. The
route and both switches live in connectonion/rem/reader.py (LIVE_WIKI_URL,
LIVE_WIKI_SERVED, LIVE_IS_DEFAULT). --local is still accepted and always
means the snapshot. If the live view says co rem is not yours, add the
browser's address as an admin of the Host: co trust admin add <address>.
The page reads each record for what it knows (#1836). A page carries one of
three tags: Mapped (an outline from your sources; its status line still says
"not investigated yet"), Some findings (written content, no investigation
pass yet) and Investigated. "Unknown" lines and placeholders are not shown;
the headings still empty are named once at the foot of the page with the
co rem investigate '<page>' command that fills them. Lists put pages with
findings first, then newest last contact. The Markdown file is unchanged, and
Copy Markdown at the foot copies it as written, unknowns included.
What the reader shows (next preview candidate)
The reader returns the context REM carried forward, then helps you recall an older page before showing its answer. It remains a point-in-time snapshot.
- Home opens with up to three pages changed in the latest pass, showing their current context and links to their sources. An explicit page link is shown as connected context; a proposed link appears separately as a question for the owner to review. Remember with REM asks about an older page and reveals what that page already says on request. Open threads keeps Waiting on you (oldest first) beside Waiting on others. This week follows. The last pass's counts and hypnogram are available in How REM processed the last pass below the memories. The owner's page is pinned as You at the top of the navigation.
- People, Organisations and Projects open as a sheet: one row per page,
the facts in columns (people: what's open next to the name, then company,
role, email, phone, last contact, mails; status is the moon beside the
name), a sticky header, sort on any column, filters (Something open,
Yours to answer, Written, Mapped only) and a text filter. A row opens
the page. It fits 1440 px; narrower, it scrolls inside itself with the cut
edge shaded and the name column held. The columns come from the notebook's
index (
store.people_table, #2067) when.state/rem.dbexists, embedded in the snapshot; before it does, from each page's Facts and the map's mail counts (index_rowsandmail_factsinreader.py,facts()in the page). - "You", not "the user": pages are written about "the user"; the reader says "you" ("you have not signed it", "How you write to them") at render time only, so the Markdown and Copy Markdown keep the words as written.
- A page opens on its lead, then a row with the first open thread
(You owe / They owe, and for how long), the last contact, and a
?when the page lists uncertainties. Its## Facts(or a legacy page's## Contact) sits beside the prose as a list: every label shown, values cited, a qualifier such as mobile as a small tag, Email, Phone and Links copyable, and a missing value shown as "— not found".## Insightlines carry Now, Changed, At stake or Pattern as a badge. History is a dated spine, Sources a footnote list, and a claim number[n]is a chip that names its source on hover or focus; three or more in a row read as "3 sources". An ASCII diagram is set on a dotted plate. A page only mapped from metadata says so at the top, with the one command that investigates it. - Search answers first: when a person's or organisation's name matches, a Best match card gives the email, phone, last contact and what is open. The rest is grouped by kind, people first, one snippet a page, never a local path.
Design: cool blue-biased neutrals with one night blue for links and one lamp
amber kept for what is owed; a dark palette of its own; Optima for titles,
Charter for prose, the system face for chrome and the mono face for every
date, count and id. Fonts are local faces, so the page makes no network
request. Every view fits a 390 px phone without sideways scrolling, keyboard
focus is visible, and the only motion (the hypnogram drawing in) is off under
prefers-reduced-motion.
To see every view on an invented notebook, light and dark, desktop and phone:
python scripts/capture_rem_reader.py OUT_DIR (the fixture is
tests/fixtures/rem_reader_notebook.py; --root COPY renders a copy of a
real notebook, and those screenshots stay local).
init is the foreground Skill workflow. start remains the explicit
background lifecycle command; initialization does not install a schedule.
Map is a stage inside rem-init, not a separate model runner.
Map reads known information before leaving basic fields unknown. It uses the single person-page definition; investigation reads that same existing page, keeps supported facts and fills gaps. The owner is investigated first. Automated notices are signals for the Skill to classify, not an automatic rule to discard companies or event opportunities.
Choose a harness
co rem config set runner codex model gpt-5.6-luna
co rem config set runner claude-code model default
co rem config set runner coai model co/gemini-3.8-flash
co rem config set runner coai model ollama/qwen3
A model name must be available in the selected provider/account. default
omits the model flag. Changing runner without a model chooses that harness's
default. Old coai configs which retained the unused Codex default migrate to
their previous effective behavior (COAI's default). No credential belongs in
co rem configuration.
The job's shape: agent or summary tier
Not every model can drive tools, and model names change under us, so the
shape of an investigation is measured rather than read off the name (#1847).
Changing model or runner runs a capability check: one investigation of a
built-in fixture page (two mails, in a throwaway notebook; none of your data)
through the configured runner, graded by code — the page must state the
fixture's fact and cite a fixture message. The result is recorded in
.state/tier.json with the runner, model and time it was checked for.
| Tier | Who gathers | Who writes the page |
|---|---|---|
agent |
co rem's code gathers; the harness reads the material with its file tools | The model writes the page file itself, as the investigate Skill says |
summary |
co rem's code gathers everything, including a project's files, and hands it all over inline (digested first if it does not fit) | The model replies with the page, one page per call; the reply becomes the candidate |
The agent tier is tried first; a model that fails it but fills the page by
reply is the summary tier; a model that does neither is not recorded and the
command fails with a Next: line. co rem config shows the tier in force.
A notebook never checked, or checked for another runner or model, runs as the
agent tier (the behaviour before the check existed) and co rem config
says so and names the command that checks it. --no-check saves a new model
without checking it.
co rem config set model gpt-6-luna # saves, checks, records the tier
co rem config # Tier: in force, checked, when
Equivalent direct CLI delegation, useful in a shell script:
co ai --json --harness codex --model gpt-5.6-luna \
"/rem-investigate Update /path/to/rem/people/alice.md; read its current content first."
The direct Skill call does not run co rem's deterministic source collection or
advance its sync cursor. Use co rem investigate for that orchestration.
COAI expands the Skill name and supplies its installed directory.
Every co rem model turn starts from the fixed .state/tasks/ workspace inside
the selected co rem root (~/.co/rem by default). Codex therefore groups
those turns under one workspace in its history. Inputs, review results and
disposable page copies live in per-run subdirectories there;
the runner validates a candidate before promoting it to the notebook.
Every co rem stage reads text other people wrote -- mail bodies and PDF, DOCX
and XLSX attachments -- and the daily job co rem start installs runs with
nobody watching. So every stage, scheduled or started by hand, runs confined:
| Runner | Flags co rem passes to co ai |
What the model can do |
|---|---|---|
codex |
--sandbox workspace-write |
Read files; write only inside .state/tasks/ and TMPDIR; no network |
claude-code |
--permission-mode acceptEdits |
Read and write inside .state/tasks/; commands, web fetch/search and reads elsewhere are denied, since nobody is there to approve them |
co rem start shows the row for the configured runner in its consent
summary, as model_permissions, before you approve the schedule, and
model_receives names whose login the model is called through (Codex or
Claude Code). Change the runner later and the next start shows the
summary again.
Model turns and the launchd job both run the installation that is running
co rem -- <its python> -m connectonion.cli.main -- not the first co on
PATH. Starting from a non-activated venv with an older co in ~/.local/bin
used to install a job, and route every model turn, through the older one.
co rem's own code fetches the mail and attachments before the model starts, so
the model needs nothing more than to read that material and write the page
copy it is given. The cost is the web: investigation no longer looks up a
role or a switchboard number with co browser, and says so in the page's
Uncertainties. Before 1.8.8 investigation ran Codex with
danger-full-access and Claude with bypassPermissions, which gave anyone
who could email the user an unattended agent with a shell, the network and
the user's mailbox; a line in the prompt was the only defence.
co rem removes an ambient ANTHROPIC_API_KEY from Claude's subprocess
environment so the run uses the selected account's subscription rather than
silently billing the API. Skills govern what the task should do; they are not
OS permission enforcement.
The removed scoped rem_* tools are no longer a filesystem guarantee.
Source coverage and output
Gmail/Outlook programmatic collection searches the requested date windows. Sync lists each weekly window 200 messages at a time and splits any window that comes back full until every half fits, so a busy week is read whole; a single second holding more than 200 messages stops the scan with an error rather than skipping them. Investigating a person on a client without a server-side search still reads at most 200 messages per weekly window. Coding investigation now walks successive batches until the cursor stops, rather than stopping at 40 messages. It searches aliases and project paths; an owner identified by mailbox address receives their own typed session messages. Injected Skill prompts are not reingested as user experience. The importer still labels oversized pasted session text as truncated.
What counts as a message you typed to Codex (#1978). Codex Desktop puts every
message in the user slot under a metadata block, typed or injected, and says
in content_item_kinds what each part is. A message whose parts are all
user.* (text, an image) is yours and is read; one that names anything else
(agents_md.instructions, environments.environment_context,
plugins.recommendations, goal.internal_context, a selected skill), or no
kinds at all, is the client talking and is skipped and counted. A message that
opens with a harness tag is still skipped, except the in-app browser context
Desktop puts in front of what you typed: that block is dropped and your words
are kept. Two kinds of thread are not read as yours: a subagent's (the
approval reviewer, a spawned worker), whose user slot the agent wrote; and the
history of a Claude Code session imported into Desktop, which co rem already
reads from Claude Code itself. What you type after an import is read. The Codex
CLI's plain three-key message is read as before. $skill-name counts in a
skill page's Usage history use the same reading.
PDF, DOCX, XLSX, PPTX (including tables/notes), plain text, HTML and ICS
attachments are read; XLSX needs pip install 'connectonion[rem]', and
without it a spreadsheet is named as unread with that command. Investigation passes full extracted text to chronological
digest chunks instead of dropping a long attachment's tail. Unreadable
formats/errors remain visible. The Skill supplements from the account's
co email service, known documents and public sites, and reports what it
could not search. Own-mail sent history currently has no paginated CLI;
Jira discovery/auth is not connected to this co rem entry point yet.
Each task supplies material and composed instructions as files, avoiding OS argv size limits. File changes are observed on disk, including deletions and partial changes on failure; a success sentence is not a file-change count. Extraction returns its written notes file, not a commentary/status reply. Nonzero exits, missing/malformed envelopes, provider errors and timeouts fail the task. Investigation is not marked finished on a failed execution.
co rem forwards its delegated deadline as co ai --timeout SECONDS and gives
the outer process 15 seconds to exit afterward. The common native adapter
therefore closes its delegate before co rem process timeout is reached.
Scheduling and accounting
launchd invokes the resolved co rem --root ... sync --scheduled CLI every
five minutes, with PATH entries for co and installed delegates. Saved local
time slots determine whether a batch is due. Repeated start reloads one job;
missed slots coalesce into one catch-up. No permanent co rem daemon is added.
Each notebook root is its own job, ai.openonion.co-rem.<hash of the root>,
the default ~/.co/rem included, so co rem start/stop under another
HOME never touches your real job. A job installed before 1.8.8b12 under
the bare label ai.openonion.co-rem is still found: stop removes it and
start replaces it, but only when its own --root is this notebook.
Sync retains its source cursor on failure. Two-stage batches reserve two attempts and cannot start with only one remaining; extraction usage survives a later maintenance failure. Reported tokens are not account quota or dollars. The input-character limit bounds gathered/digested material, not every tool read a delegated agent may perform.
Codex quota (#1843)
With the Codex runner, the notebook reads your Codex plan's own meter: the
weekly window's used_percent, its length and when it resets, as
codex app-server reports them (account/rateLimits/read). Reading it starts
no model turn and costs nothing. Codex reports whole percents, so every figure
below is good to about one point.
- Every run records the meter before and after (
quotain the run log, shown byco rem logs). The difference is what that run cost in points of your week, measured rather than estimated from tokens. - A run the meter cannot see is counted from its tokens (#1990). Codex
reports whole percents, and on the 1.9.0a7 acceptance notebook the week read
29% before and after every run, 3.4M input tokens in all, so the budget said
"0 of 10 points" all week. A run whose reading did not move (or could not be
read) now counts
(input − cached input + output) / 1,000,000points, to one decimal: about a million tokens the model had to read fresh or write is one point. A run that did move the meter counts what the meter says. - Investigation has a weekly budget,
limits.investigation_quota_points, default 10 points of the weekly window (owner, 2026-09-27). The scheduled round adds up the points its investigation runs used since the window last reset, and starts no new page once that reaches the budget. - Manual investigation counts too (#1842).
co rem investigate PAGE,meand CATEGORY runs record the meter like the round does, and their points count toward the same weekly budget. A CATEGORY run stops starting pages when the weekly budget is spent, when its own--budget Nis spent, or at the floor, and says which; the page in flight finishes. - The first pass after init is
co rem investigate all --budget 10: one queue over people, projects and organisations by weight (the same order the round uses), until 10 points of the week are spent.--listshows that order without running a model. - A floor protects your own coding. No investigation page starts once the
week is at
limits.quota_floor_percentor more, default 70%, however much of co rem's budget is left. co rem shares this quota with your real work. co rem statusreads the meter now and says it in two lines, for exampleCodex week: 5% used on pro; resets Sun 04 Oct 09:49andInvestigation this week: 0.7 of 10 points; nothing starts once the week is at 70%. The dashboard says what a point is under the line.--jsongives the same numbers underquotaandinvestigation_quota.- When the meter cannot be read (another runner, Codex not signed in, an older
Codex), the run says
quota: unknown (<why>)and the daily call cap (limits.runner_calls_per_day) is the only bound, as before.
Maintenance is not quota-gated: it is the incremental daily pass and stays bounded by the call cap. Its cost now shows in points, so a cap can follow from real numbers. This supersedes the earlier unimplemented 2% initialization / 1% daily targets, which needed exactly this meter.
The scheduled daily round maintains first. The first run of the local day then investigates unfinished pages, most recent activity first, within a reserved share of the daily attempt cap (8 calls; a person is one investigation); every later run updates only the people with new mail and the projects with new messages since the run before, at most 5 pages. Both stop at the weekly budget or the floor and record how many pages are left (details). Initialization currently builds the map without a model call; manual investigation remains outside the scheduled cap.
The UI is a static snapshot of the notebook as it is now; run open again to see later changes (--no-launch says so and ends on co rem open). No merge,
release, new background job, broad mailbox backfill or production co rem rewrite
is implied by the architecture refactor.
See acceptance evidence.
Inspect one skill's retained run evidence
co rem --root /path/to/rem investigate skills/catalog/example.md --eval-dir /path/to/.co/evals
Skill pages dispatch to a local, deterministic collector instead of the mail/model
investigation pipeline. Omit --eval-dir to use ~/.co/evals; repeat it for
additional summary directories. The collector reads immediate summary YAML files
(up to 1,000 per directory, 4 MB each), matches exact /skill-name inputs, and
deduplicates retained run/turn identities. It writes a linked note containing
inputs, retained outputs, reported tool calls, recorded evaluations and coverage.
The skill page gets a managed Run evidence block; curated sections and the
existing investigation stamp are preserved. This is evidence gathering, not
a completed quality assessment.
Counts describe observed invocation attempts, not proven starts or lifetime runs. Tool-invoked skills and other harnesses are not yet covered. Historical outputs may be missing, current summary model labels may not establish each run's model, and same-name installed copies cannot be attributed. Goal achievement and verified changes stay unassessed until actual artifacts are checked.
1.8.7 integration update
co rem --root '<root>' init --days 150 now builds people, projects and installed
skill maps deterministically. The map invokes no model. (Since #1943 init then
writes your own page in a terminal; see Start here.)
Only enabled mail sources are read. Use subscriptions and explicit subscribe
commands to select sources first. The map records counts, dates and coverage in
.state/map.json and writes people/project indexes under notes/; it leaves
classification unassessed. The rem-init Skill can subsequently rank that map.
Run investigate <record> explicitly for one page.
Investigation reads a normalized skeleton and writes a new candidate under
.state/tasks/. Only a candidate with valid structure and reference definitions
replaces the page. Failed candidates remain for diagnosis. This check cannot
establish factual correctness. Full source JSON is retained; a readable copy uses
reversible text chunks so line-limited tools can read all of it.
The requirement-to-code/test checklist and remaining decisions are in rem-187-checklist.md. This update supersedes earlier references to init launching a model or investigating the owner in the same run; #1943 later brought back that one step, for the owner's page only, by the owner's decision.
First-run People and installed Skills
co rem init runs without questions in terminals and scripts. It uses connected
mailboxes automatically and prints co auth google / co auth microsoft tips for
disconnected sources after building the local maps. Authenticate and rerun init
to add People. To restrict mapping to a specific mailbox:
co rem init --mail outlook
# or: co rem init --mail gmail
co rem init --days 5 # small first-run trial
co rem open
This lists 90 days of mail by default: correspondent metadata plus the short
preview the provider lists with each message. A seven-day window that fills the
provider's 200-message listing cap is split until every message in it is
listed, so a busy week is no longer cut off at 200 without a word. Init does not
install a schedule. It subscribes the mailboxes it read, so start offers them,
but nothing is read in the background until start is approved.
Private mail materials
After the map, init saves each listed message body once, so investigating a
person later reads the saved window from disk and only asks the mailbox about
mail outside it. Everything lives under the notebook's .state/, which is
owner-only (0700 directories, 0600 files) and never shown to a model as a
page or sent anywhere:
| File | Holds |
|---|---|
.state/source-inventory.md / .jsonl |
What was listed, window by window: ids, dates, senders, recipients, subjects, session paths. No bodies, no previews |
.state/mail/messages/<provider>/<hash>.json |
One provider-rendered text body per message. Attachments are not downloaded |
.state/mail/people/<hash>.jsonl |
Each person page's messages, by reference; a mail to three people is stored once and indexed three times |
.state/mail/projects/<hash>.jsonl |
Each project page's local session files, by reference |
.state/mail/archive.json, summary.md |
Range, counts saved / reused / failed, and status |
Pages never contain a raw body. A body that could not be fetched marks init
partial with a nonzero exit; rerunning reuses every saved body and fetches
only the rest. If a later init cannot list a mailbox, the earlier archive is kept
rather than replaced. --no-mail-archive skips the body download and keeps the
metadata-only map. Investigating a person or an organisation reads whatever
part of the archive is saved, even while it is still being saved (#2042): the
mailbox is still listed for the window, but a message whose body is on disk is
not fetched again, and coverage says how much of the archive there is
(12 loaded from private init archive (2,693 of 3,152 bodies saved so far)).
The per-person indexes are written whenever the archive pauses, not only when
it finishes. A sync that resumes the archive says so, with its progress:
Saving mail bodies: 1,200 of 3,152.
A person is named, in this order, by the name they write under, the name in the
owner's saved contacts (Google contacts and "other contacts", Outlook contacts;
skipped when the login cannot read them), and the owner's own greeting in a mail
to that one person ("Hi Larry,", "Larry 你好,", "子明,"). A greeting to several
people names none of them. On the owner's notebook this named 176 of 195 people
the map had titled with a bare address. An organisation is the registrable
domain (accounts.google.com and google.com are one), and a domain only notice
senders write from gets no page. A page still titled by a bare address whose
sender the owner never wrote to is held for review: kept, but left out of the
investigation queue, co rem list and the reader's contents. co rem list people --review shows them; a later init that finds a name or a reply from the
owner, or investigating one by its path, brings it back. A nameless address the
owner has written to, the agent's own included, stays an ordinary page, and an
investigated page is never held -- except one the owner only ever writes to and
never hears from, the shape of their own other mailbox: it is held too, and
still asked about with init --mine (#1987). A sender whose display name is its
own domain ("Airbnb" discover@airbnb.com, "Google Cloud" googlecloud@google.com,
"X" notify@x.com) and who writes at least three times as often as the owner
answers is a service: listed with the notice senders, no people page, and an
older map's page for it that holds only map output is archived. Someone writing
from their own name at a domain named after them (aaron@aaron.dev) stays a person.
Skills and projects are one page per skill name and per repository (below). With --mail, only explicitly selected
mailboxes are read. Missing or failed sources appear in the mapping coverage;
without a selected mailbox the command explains why People is empty.
The terminal shows one line per mapping stage, a short count of People,
Organizations, Projects and Skills, and your own page's facts. Full per-source details stay in .state/map.json under the
co rem root and in --json output. A custom --days window is preserved in the
printed next command and retry tips.
Skills lists one catalog page per name; the page lists each installed copy and says which differ. The generated index is not counted as another skill.
One page per repository
A project is its repository, not each folder a session ran in (#1974). A git worktree folds into its main checkout's page:
- a folder whose
.gitis a file sayinggitdir: <repo>/.git/worktrees/<name>belongs to<repo>; - a folder under
<repo>/.claude/worktrees/belongs to<repo>, even after Claude Code removed it; - a folder under
.worktree/or.worktrees/that no longer exists belongs to the repository beside it whose folder name starts its own (~/projects/.worktree/browser-139→~/projects/browser); with no such repository it is left out rather than guessed.
Paths lists the repository root and a count, not the worktrees:
## One count for every screen (#2008)
The reader said "174 with findings" when three pages had been written: a mapped
skill page shows its description and a mapped project page its paths, and both
read as findings. People were 76 on one screen and 82 on another, skills 159 and
152. Now `connectonion/rem/census.py` is the only place that decides, and the
reader and `co rem status` both ask it:
- **Counted**: people, projects, organisations and skill catalog pages. Not
counted: pages held for review (no name, never written to), services and
automated senders that still have a people page, and the skills index.
- **Written**: a page someone or a model wrote — its status line no longer says
"not investigated yet". A merge keeps the investigated page's status, so a
merged page counts exactly when what it kept was written. A mapped page with a
description or paths is not written.
- **Last activity**: the page's own date — the last contact of a person, the
last session of a project, the date of its last investigation — never the
file's modification time, which is when the last map rewrote it. "Recently
active" in the reader lists written pages by it and shows it.
## Facts and Insight on every page (#2068)
The owner, many times: an investigation finds too few facts and too little
insight, and on Ody's page the phone number could not be found at a glance. A
page now opens on a **Facts** block — one field a line, each value cited, a
missing value visibly `Unknown` — and a short **Insight** section; the prose
sections follow. `connectonion/rem/facts.py` owns the shape; the reader renders
the block as a card.
### The data shape (what the reader reads)
```markdown
## Facts
- Email: mia.chen@harbour.example
- Phone: +61 2 5550 0142 (work) [1]; +61 400 555 019 (mobile) [3]
- Company: [Harbour Analytics](../orgs/harbour-analytics.md) [1]
- Location: Unknown
- The section is
## Facts. On a person page it comes straight after the lead; on a project page it is the first section; on an organisation page it followsDomains. - One line a field:
- <Label>: <value>. Every label of the page's kind is always present, in this order, spelled exactly:- person: Email, Phone, Company, Role, Location, Time zone, Links, How we know them, First contact, Last contact, Signing entity, Handles, Language, Also known as
- project: Repository, Stack, Status, People, Organisation, Started, Last activity
- organisation: What they do, Website, Location, Legal entity, Your contacts, First contact, Last contact
- An empty field is exactly
Unknown. - A field with several values separates them with
;. Each value may end in a(qualifier)(work,mobile,personal) and then its citations[n], which are numbers defined under## Sourceslike every other claim. A value may be a Markdown link. - Dates (
First contact,Last contact,Started,Last activity) areYYYY-MM-DD. - Every value carries a citation, except
Email,HandlesandAlso known as, which the map fills from the addresses it found. A citation at the end of a line covers the uncited values before it (UNSW Founders; [UNSW](../orgs/unsw.md) [12]); a full stop after it is ignored. A new value with no citation is taken off the page when it is saved (review.json:facts_uncited_dropped) rather than refusing the page.
facts.parse(page) returns {"Phone": [{"value": "+61 2 5550 0142", "qualifier": "work", "citations": ["1"]}, …], "Location": [], …} (an empty
list is Unknown), so the reader, the People table and a later database
(#2067) read the same thing. A page written before 1.9.0a9 has ## Contact
instead: facts.upgrade renames it and adds the missing labels as Unknown
the next time an investigation or maintenance writes the page; facts.parse
reads either.
Extracted before prose
Before the model turn, connectonion/rem/fact_extract.py reads the gathered
material with no model: the subject's own addresses, phone numbers in their
signature blocks (with work / mobile from the line's label), LinkedIn
links, the dates of the first and last message, the signature block itself,
the lines of calendar invitations that name the subject, and the company domain
when it is not a mailbox provider. They go to the turn as the
investigation:facts item, each with its source id, even when the rest of the
material is in files to search — the turn confirms them, extends them and
cites the source id, not the item.
The model may correct a fact the material contradicts; it may not lose one.
After the turn, a phone, address, LinkedIn link or contact date the extractor
found that appears nowhere on the page is put back into its field with its
source (review.json lists it under facts_restored). Company and role from a
signature are context, not restored: reading a title off a signature is a
judgement.
Insight
A short section after Facts on person and project pages (the owner's own page
too, where it is the owner's month: what shipped, who is waiting): two to four cited bullets of what the inbox does not say outright, each
starting with its kind, which the reader shows as a badge —
- Now:what this person or project is to the user's work today;- Changed:what moved recently (a new role, a stalled thread, a price);- At stake:what is at risk or owed, by whom, since when;- Pattern:something over time (replies within a day until August, then nothing; every mail is about invoices).
Generic lines ("a key stakeholder", "a valuable relationship") are not insight;
the benchmark refuses them. Thin material says - Unknown.
The lead above Facts carries the one line a reader opens the page for (#2065):
a person's states the balance — who owes whom what, and for how many days, or
Nothing open as of <date>; a project's says where the user stopped, what is
next and what blocks it. A claim is stated once in one clause; doubt goes once
in Uncertainties, and how the page was made (the mapper, the collector, how
many mails matched) goes nowhere in the body — that is the run's record.
Fact coverage
facts.coverage(page) is the share of a page's fields that are filled; an
investigation's result carries facts — fields filled before and after, the
facts the extractor found and how many of them the page kept.
Measured on a copy of the owner's notebook (2026-10-02), fields filled of 14: Ody 6, Tamara 7, Richard 6, the owner's own page 3. The material held more than each page had: Ody's phone (in a signature), every page's first and last contact, and on the owner's page a phone, links, company and role. After re-investigating with these skills, Ody went to 8 (9 with the restore step over the full window; the run was a quick pass of the newest mail) and Tamara to 11, her mobile among them, each with three labelled Insight lines.
When an investigation finds nothing new, the restore step still runs: a page
whose cited mail carries a phone the page lacks gets it back with no model call.
In a quick pass (--quick), the extractor sees only the sampled mail.
co rem status (#1996, #2008)
- Every time is in the notebook's timezone (
schedule.timezone), the last run included; UTC only when none is saved. - A run whose process is gone on this machine (Ctrl-C, a closed terminal, a kill) shows interrupted at once. Status stays read-only: the next command that writes runs closes the record, as before.
- Today's tokens add up every run that reported usage — investigations included, which the day's total used to leave out — and say "N runs without usage" instead of turning the total into "unknown".
People ●○○○○○○○○○ 3 of 82 4%is the census above, the same as the reader.- The budget line says its unit: points are percent of the Codex week, moved by investigation runs only. Maintenance runs are bounded by the daily call cap, so a day of maintenance tokens beside "0 of 10 points" is not a contradiction, and the line now says so.
Nextis the first thing under "To write next" (co rem investigate meon a notebook whose own page is still mapped), thenstartorlogsas before.
How co rem's results are laid out (1.9.0a9)
status, doctor, the sync summary and the map init prints share one
layout, so it is learned once:
co rem status · running in background (launchd)
next slot 07:00
Today 7 pages changed · 248 items read · 3 runs
1.7M tokens in · 20k out
Notebook ~/.co/rem
People ●○○○○○○○○○ 46 of 312 15%
Skills ●●●●●●●●●● 154 of 154 100%
● written ○ mapped, not written yet
Mailboxes
✓ Gmail read by the daily round
✗ Outlook connected, but not read by the daily round (not subscribed)
→ co rem sources add outlook
- One title line; what the state asks for goes under it, not after it.
- A section label in the margin, every value at column 17, one item a line. Status leads with today, because the notebook consolidates overnight.
- Counts are bold and right-aligned; tokens read as
812,91k,1.7M(the exact numbers are in--jsonandco rem logs). - Glyphs mean one thing each:
●written,○mapped but not written,✓fine,✗needs a fix,↻unfinished and resumable,→the command that fixes the line above. They print the same in a pipe; only colour is dropped. - A long value wraps under its own column in a terminal, never at the margin.
- Colour by role from
connectonion/cli/style.py: commands cyan, counts bold, paths and notes dim, the green of a finished state as the one accent (the meter,✓, every progress bar), yellow for what needs a fix. - Progress: one live line per stage (spinner, what it is doing, a 24-cell bar,
i/Nbold, elapsed dim); a finished stage leaves✓ what it found.
What sync prints, and where the tokens went (#2043, #2044)
co rem sync says each page's outcome as it finishes, not in a dump at the end:
Investigating people/ada-1f2e3d.md…
✓ Updated people/ada-1f2e3d.md (accepted)
✗ Refused people/bob-4a5b6c.md: over 20,000 characters
and ends with a short summary instead of the whole run record: new material
read, the pages updated / refused / with nothing new, how many are left, the
mail archive if a sync is still saving it, the run's tokens, and the command
that shows the full record (co rem logs RUN). Off a terminal the words are
the same, without colour. A long investigation off a terminal prints a stage
once when it starts (Investigation: gathering codex sessions), not once per
40 files scanned.
co rem logs --usage puts every model run under a stage, so the stage totals
add up to the total: extract and maintain for sync batches,
investigate for people, organisation and owner investigations (by hand or in
the daily round), and projects for project pages. A run recorded before it
split its usage by stage is counted under the stage its kind implies. Tokens are
credited to a source only by a sync batch that read that source's items; an
investigation reads many sources and is not split across them. Tokens per 1k
characters is measured on sync batches only: an investigation's material goes
into files the model searches, so its characters are not what it read.
Tidying a notebook made by an older version (#1999, #2008)
Maps get better, and the pages an older map made stay. An upgraded notebook
kept services as people (Apple ID, notify@x.com, GitHub's unsub+… reply
addresses, D&B, Microsoft), two of the owner's own addresses as people still
queued for investigation, three pairs of pages for one skill, and old pages
still carrying web: not searched … and investigation:coverage citations.
Tidy runs by itself, at the start and again at the end of every map
(co rem init; the pass at the end leaves the owner's own addresses to the
next run, because the map has just asked about them), and at the start of every
sync (the daily round and co rem sync), under the notebook lock. It is
idempotent: a tidy notebook is left exactly as it is, and nothing is written
when nothing needs tidying. No model is called. What it does:
| Found | Done | Undo |
|---|---|---|
A people page for a service or automated sender, never investigated (the map's automated_correspondents, the #1987 service rule, or an automated address) |
moved to .state/archived/people/… |
move the file back |
| A people page for an address that is clearly the owner's: never replied to, and the address or display name carries the owner's name or an address the owner already confirmed | folded into the owner's page (merge.merge_into: written lines kept, page archived, record an alias); the address added to the owner's addresses |
.state/aliases.json names the archived copy |
Two catalog pages for one skill (a SKILL.md without a name: takes its folder's name, so ~/.codex/skills/changxing-nonfiction-refine and ~/.agents/skills/nonfiction-refine were two skills) |
folded into the page of the named skill, as the map does for copies | as above |
An organisation page for a mailbox provider (gmail.com, yahoo.com.hk, outlook.com.au, qq.com, 163.com …) or an event platform's relay domain (luma-mail.com), never investigated |
moved to .state/archived/orgs/… |
move the file back |
A line - web: not searched …, or a Sources entry [N] investigation:coverage … and its [N] markers |
that line or marker removed; every other line kept | the removed text is in the log |
An investigated page is never archived or folded: a person's work on a page is
not undone by a rule about its address. Every action is appended to
.state/tidy.json with the page, what was done and, for removed lines, the
line itself. The sync result and the map report carry tidied, what moved, by page.
A real person is never folded into the owner. "Possibly yours" — the
addresses init offers to confirm with --mine — lists only addresses that
never replied and carry the owner's own name or confirmed address in the
address or its display name. The owner's notebook offered seventeen, fifteen
of them colleagues and friends who answer on other channels; the list now holds
the two that are the owner's. An address confirmed once (--mine, or folded by tidy)
stays the owner's at the next map without repeating --mine.
Why twice (#2018). The 1.9.0a5 acceptance run's map made
team-telnyx (discover@telnyx.com) and held pages for Workday's OTP sender,
Singapore Airlines' booking@, Lebara's mylebara@ and Telnyx's portal@,
and tidy, run before that map, had nothing to act on. The map and tidy ask one
question (map.service_page), and it now also covers:
- a role desk that only writes in:
portal@,booking@,bookings@,reservations@,discover@,otp@,verify@,security@,account@,orders@,welcome@,members@; - a sending platform (
myworkday.com,workday.com) or anotp.sending subdomain, the waymail.andnews.already were; - an address whose local part carries the domain's own name (
mylebara@lebara.com.au) and that the owner never wrote to; - a display name with the domain's name anywhere in it ("Team Telnyx"), not only first.
So a fresh map makes none of these, and tidy at the end of the map archives a
page the map before it made. A mailbox provider is never an organisation:
the list of known providers is kept, and a provider's name under any country
suffix (yahoo.com.hk, hotmail.co.uk, outlook.com.au) is one too; an event
platform's relay (luma-mail.com, 253 mails from one sender) makes no
organisation either.
The owner's page is rewritten, not appended to (#2017). The acceptance
run's owner page carried nine "Possibly also the owner's" lines, the same
three addresses at different counts, two of them already confirmed and folded,
and History still said "In the 90 days to 2026-09-25" after a re-map. Each map
now replaces every "Possibly also the owner's" line with the current list, and
replaces its own History lines ("In the N days to …", "Most mail with …",
"Coding sessions in the same window …") and its [1] enumeration source with
today's. Tidy drops the line of an address it confirms or folds. Other lines
are never touched.
Measured on the same copy after 1.9.0a5's tidy (never the notebook itself):
people pages 357 → 349 (8 more services: Telnyx's portal, Singapore Airlines'
booking desk, both Workday senders, Lebara, TEN13's community desk,
"Partnership LexGeneris", "Swim School UNSWFAC"), held pages 25 → 19,
organisation pages 142 → 140 (yahoo.com.hk, luma-mail.com), "Possibly also
the owner's" lines on the owner's page 9 → 0. A second pass changed nothing.
A fresh map no longer makes the duplicate skill pages either: a skill named
after its folder joins the named skill whose name its folder ends with
(changxing- + nonfiction-refine) when the two copies are the same file or
carry the same description.
Measured on a copy of the owner's notebook (2026-10-01, never the notebook
itself): people pages 381 → 357 (22 services archived, 2 own addresses folded),
skill catalog pages 153 → 150, "possibly yours" 17 → 0, pages with
web: not searched 4 → 0, pages citing investigation:coverage 5 → 0 (9
lines removed). A second pass changed nothing.
Paths
- /home/you/projects/connectonion
- Worktrees: 49
- Sessions: 116
The main checkout is one branch's working tree, not the project's state (#1982).
On the owner's machine it sat on an August branch, and the page said version
1.8.0a3 the week 1.9.0a3 shipped. So an investigation hands the turn one
`checkout-state` item per listed checkout, cited as `git:<path>`: the branch it is
on and its HEAD's commit date, the project's current line (`origin/HEAD`, else
`origin/main`, `origin/master`, `main`, `master`, else the most recently committed
branch) with its last commit date and the version in its `pyproject.toml` or
`package.json`, and -- when HEAD is more than 14 days older than the project's
newest session -- a line saying the checkout's files are not the current state
and the version comes from that line instead. The file list is unchanged; the
turn is told which of what it reads is stale.
Some folders are not projects, and the map leaves them out (`not_a_project` in
`rem/scan.py`):
| Folder | Why |
|---|---|
| your home folder, or above it | it holds every session there is (#1944) |
| inside a hidden folder (`~/.claude/plugins/cache/…`, `~/projects/.artifacts/…`) and not a git repository | a cache, a plugin install or build output |
| a Claude Code scheduled-task folder (`…/scheduled-tasks/…`) | a task's working folder |
| not in a git repository, one session, at most 3 messages you typed | a one-off chat (`create-a-scheduled-task-called-weekday`, a plugin install folder) |
A folder with two sessions, a repository, or a longer conversation stays a
project. System temporary directories, removed Codex worktrees, co rem's own task
copies, fixture notebooks and multi-repository workspace containers stay out as
before.
A notebook mapped before this has split and junk pages. The next map merges
them: every existing page listing one of the repository's paths (worktrees
compared as their main checkout) folds into one page — the one with the most
written content, so an investigated page is never merged into an empty one.
Written lines of the other page are merged section by section with citations
renumbered, its message material under `.state/projects/` is merged too, and the
page itself moves to `.state/archived/` with its record kept as an alias
(`.state/aliases.json`). A junk folder's page that holds only map output is
archived; one somebody wrote in is kept.
### Preview reliability checks
Initialization reports partial failure with a nonzero exit if a selected mail source cannot be initialized or read. Completed maps remain available; provider error text is not exposed. Recovery commands retain the notebook root. Automated-looking correspondents are explicitly labelled candidates, not silently certified as people.
Your own page has its own spec (#2008), the `rem-owner-page` Skill, composed
after the person page only for `investigate me`. It leads with who you are and
what you are working on now, from your coding sessions (the projects and what
you did in them, dated); your roles appear only when you state them about
yourself or someone states them about you, never from a list you wrote about
someone else (a real page took "Partner at OpenOnion, running marketing" from
the owner's own description of a partner); `Open threads` is what you owe and
are owed; `History` is dated events, not the map's mail counts. It has no "How
the user writes to them" section. The same attribution rule is in
`rem-investigate-person` for everyone: a role in a list the user writes about
someone else is that person's.
init runs the whole `co rem investigate me` for you. `--quick` is a bounded
pass that samples recent items across available source types and labels the
result partial; it is only for `me`, and neither mode approves a candidate
without review.
`co rem investigate <page> --days 5` reports source gathering, evidence
preparation, extraction chunk counts when the material exceeds one model turn,
and candidate writing in its run log and terminal. A failed model or provider
call exits nonzero and keeps the page unchanged. Project investigations may
inspect a bounded set of files in the page's recorded local Paths; the file
inventory is a lead, not proof of file contents. Review the candidate and its
citations before treating it as a verified notebook page.
Completed extraction chunks are checkpointed under `.state/extracts/investigate/`;
rerunning the same evidence and model settings can reuse them after an
interruption. The running log records the current chunk and usage from completed
chunks. A changed source or extraction prompt invalidates the checkpoint.
Repeated mapping refreshes generated project counts, dates and paths while preserving written notes. Skill pages retain authored descriptions and show current installed metadata in a separate managed section. Unchanged content is not rewritten. Equivalent SSH/HTTPS Git remotes share an identity; distinct case-sensitive repository paths remain distinct. Search groups skill installations just like the catalog, and the homepage labels its content as a snapshot rather than claiming every skeleton is maintained.
## Reflections, review and staged investigation
See [co rem memory workflows](rem-memory.md) for `reflect`, `review`, `capture`,
`route` and `daily`, including provider, retention and budget limits.
ConnectOnion