Stage 10 design review
Status: accepted for implementation. Scope: native watcher and workspace full read. Date: 2026-11-09.
This review precedes the code, as the roadmap gate requires. The design keeps the deterministic core, the standard-library-only install, and the existing polling fallback.
Goals
- Wake the watcher on file changes through the host native API: - inotify on Linux; - FSEvents on macOS; - polling on other platforms or when a native API is unavailable.
- Add a workspace-level full-read runner over several indexed repositories:
- one plan that spans repositories;
- qualified chunk ids (
repo:chunk-id); - a workspace coverage ledger; -plan,next,read,done,status, andverifycommands. - Record the stage evidence in the roadmap and benchmark pages.
- Keep every new behavior testable without a model or network.
Non-goals
- A daemon manager, systemd unit, or launchd unit.
- Watch support for remote filesystems that do not deliver native events.
- A second copy of the per-repository index.
- Cross-repository categories as first-class nodes.
- Model-generated labels or embeddings.
Watcher design
Backend interface
available() -> bool
wait(timeout) -> (changed_paths, overflow)
close()
auto chooses inotify on Linux, FSEvents on macOS, and polling elsewhere.
An explicit --backend is for tests and troubleshooting. If a native backend
fails to initialize, the watcher prints one warning and falls back to polling.
Linux inotify
- Use
ctypesagainst the C library; no new dependency. - Watch every included directory recursively with
IN_CREATE | IN_DELETE | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE_SELF | IN_MOVE_SELF. - Add a watch when a new directory is created or moved in.
- Skip the same directories and
.auwai-ignorepaths as the index walk. - Read non-blocking events with
select. Coalesce a batch into one refresh. - Treat
IN_Q_OVERFLOW, a self-delete, or a directory event as a reason to run the fullscan_oncepath. - Close the descriptor on exit.
macOS FSEvents
- Use
ctypesagainst CoreServices and CoreFoundation. - Create a file-level event stream for the repository root with no defer and root-watch flags.
- Schedule it on the current run loop and drain with a bounded run-loop call so
--max-secondsstill exits. - Convert absolute event paths to repository-relative paths.
- Fall back to polling if the framework calls fail.
Refresh path
An event batch uses the existing incremental refresh:
native event batch
-> changed relative paths
-> refresh_if_stale.py
-> store.sync_changed
-> watch-state.json
A batch larger than --max-files uses the existing full rebuild path and a
full ledger sync. A missing state file or an overflow uses scan_once.
The watcher never edits source.
CLI
auwai watch --repo PATH --backend auto
auwai watch --repo PATH --backend inotify --interval 1
auwai watch --repo PATH --once
--once is unchanged and always uses one stat scan.
Tests
- On Linux, create a file and assert the inotify backend reports it and the ledger updates.
- Assert an unavailable backend selects polling, and an explicit unavailable backend fails clearly.
- Assert ignored paths do not create watches.
- Assert a missing ledger is bootstrapped by one scan.
- Keep the existing
--onceCLI test.
Workspace full-read design
State
<workspace>/.auwai/workspace/
fullread.json plan, policy, segment state
coverage.sqlite workspace coverage and segment completion
findings.md existing workspace findings
fullread.json stores the plan produced by workspace survey and a status per
segment. coverage.sqlite is the workspace coverage ledger. It is separate
from the per-repository ledgers on purpose: a segment can span repositories and
the target may not be a repository.
Schema:
CREATE TABLE chunks (
repo TEXT NOT NULL,
chunk_id TEXT NOT NULL,
path TEXT NOT NULL,
read_at TEXT,
complete INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (repo, chunk_id)
);
CREATE TABLE segments (
segment_id TEXT PRIMARY KEY,
status TEXT NOT NULL,
started_at TEXT,
done_at TEXT,
tokens INTEGER NOT NULL DEFAULT 0
);
Plan
workspace fullread plan builds the same virtual tree and segment plan as
workspace survey, then persists it. A plan is refused if an existing plan is
unfinished unless --force is passed. --force resets the workspace coverage
ledger and the segment state.
The plan records:
- workspace name and root;
- policy: context window, fixed prompt, reserve, safety, segment budget;
- repository names and qualified chunk counts;
- every segment with its qualified
chunk_ids; - the plan id, a hash of the policy and segment skeleton.
Read loop
workspace fullread next
-> first pending read segment
-> mark active
-> print brief and qualified chunk list
workspace fullread read [--segment ID]
-> read each qualified chunk from its repository
-> print line-numbered bodies
-> mark chunk coverage complete
-> keep the segment active
workspace fullread done [--segment ID] [--summary TEXT]
-> mark the segment read and complete
-> append a workspace finding when --summary is present
-> print progress
workspace fullread verify
-> list planned chunks with no complete coverage
-> exit 1 when any remain
A synthesis segment is listed after the read segments. It has no chunk bodies;
done closes it after the findings review. The runner does not call a model.
The agent, or a model harness, drives the loop.
Invariants
- A chunk id is always qualified at the workspace boundary.
- A chunk belongs to exactly one repository.
- Coverage rows are inserted when planned and updated on read.
- A segment cannot be done before it has been read, unless it is a synthesis segment.
- Re-running
planwithout--forceis a no-op that prints the existing plan. - The workspace ledger survives a crash; a stale active segment can be read again idempotently.
- The per-repository ledgers remain authoritative for per-repository reads. The workspace ledger is the coverage record for the virtual repository.
CLI
auwai workspace fullread plan --workspace demo --context-window 65536
auwai workspace fullread next --workspace demo
auwai workspace fullread read --workspace demo --segment read-1
auwai workspace fullread done --workspace demo --segment read-1 --summary "..."
auwai workspace fullread status --workspace demo --json
auwai workspace fullread verify --workspace demo
Tests
- Build a two-repository workspace, plan, read, done, and verify.
- Assert every planned chunk has a coverage row.
- Assert a segment spanning two repositories reads both.
- Assert
--forceresets coverage. - Assert duplicate reads are idempotent.
- Assert
verifyexits nonzero before completion and zero after. - Assert a missing repository or chunk fails with a clear error.
Rollout
- Land the watcher backend and workspace runner behind their new commands.
- Keep the existing polling and survey paths unchanged.
- Run the full suite and the new stage tests.
- Record the stage evidence in the roadmap and metrics pages.
- Do not tag or publish as part of this stage.