Short operating manual for AI agents working in this repo.
These must always hold true:
-
Don't ask to keep going. When there are well-defined tasks to begin, delegate them immediately. Keep going until actually blocked (waiting on Tom, missing information, file conflicts, etc.).
-
Capture follow-up work immediately. When any task (including subagent work) surfaces follow-up work, create a triage task card in
.tasks/triage/right away. Don't just mention it — file it.
- Wishes inbox:
.wishes/ - Triage inbox (unowned follow-ups):
.tasks/triage/ - Task queue:
.tasks/{triage,backlog,active,done}/ - Gap backlog (canonical map: update→delegate):
research/zig-cr/92-gap-backlog.md - Delegate handoff log (canonical claims: delegate→update):
.tasks/DELEGATE_WORK_HANDOFF.md - Zig implementation:
zig/ - TypeScript specs (source of truth):
effect-native/.specs/ - TypeScript packages (current reality):
effect-native/packages-native/ - Upstream reference context (read-only):
.refs/effect/,.refs/effect-smol/- Effect SQL refs:
.refs/effect/packages/sql/,.refs/effect/packages/sql-sqlite-bun/
- Effect SQL refs:
- All TypeScript work happens in the
effect-native/submodule. - For any TS change:
- Read and follow
effect-native/.specs/AGENTS.md. - Treat
effect-native/.specs/*as the single source of truth.
- Read and follow
Every .tasks/**/TASK-*.md must include:
Files to Modify(tight scope)Acceptance Criteria(testable)Parent Docs / Cross-links(bidirectional links)Progress Log+Completion Notes
Rules:
- Hard rule: no two concurrent tasks (including subagents) touch the same file.
- Before starting any work, cross-check
Files to Modifyagainst everything in.tasks/active/.
- Before starting any work, cross-check
- One task card = one owner = one atomic commit.
- Use
.tmp/for temp files (never/tmp/).
When any agent (including subagents during “Delegate work”) discovers follow-up work, it must be captured as a draft task card in .tasks/triage/.
Rules:
- Follow-ups start in triage. Do not begin them automatically.
- One follow-up = one new
TASK-*.mdfile in.tasks/triage/. - Include minimal but real scope:
Files to Modify,Acceptance Criteria, and links to the triggering task/spec/PR. - Prefer a crisp title that describes the gap, not the fix.
Intent:
- Keep an explicit inbox for newly discovered work.
- Make follow-ups impossible to “forget” between delegate rounds.
Workflow:
- List
.wishes/*.md(not subdirs). - Pull constraints/requests into planning.
- If satisfied, move to
.wishes/done/and append: date, what changed, commit hash. - If blocked, move to
.wishes/blocked/and append the reason.
Primary goal: identify and unblock the 0.16.300-preview release.
Meaning: reconcile intended docs/specs vs built reality, then refresh .tasks/.
"Delegate work" and "Update tasks" are an adversarial collaboration loop:
- Delegate phase writes claims + evidence into
.tasks/DELEGATE_WORK_HANDOFF.md. - Update phase tries to invalidate those claims by reconciling specs vs implementation.
- Gap backlog (
research/zig-cr/92-gap-backlog.md) is the opposite evergreen handoff (update→delegate).
Do this, in order: 0. Anchor on the release tracker:
- Treat
.tasks/backlog/TASK-209-release-0.16.300-preview.mdas the source of truth. - Any discovered gap must become either:
- a checked/unchecked blocker line in TASK-209 plus an owning task card, or
- a triage task explicitly marked "not a release blocker" with rationale.
- Read the delegate evidence first:
.tasks/DELEGATE_WORK_HANDOFF.md- Treat it as claims to falsify.
- Prefer using the captured test output + coverage notes to avoid rerunning expensive tests.
- If evidence is missing (no commands, no output, no repro steps), assume the claim is unproven.
- Snapshot the inbox + queue:
.wishes/*.md.tasks/triage/(triage inbox).tasks/{active,backlog,done}/
- Reconcile implementation vs intent:
- Zig: compare
zig/toresearch/zig-cr/*(esp.90-feature-matrix.md,93-phased-execution-proposal.md). - TS: compare
effect-native/packages-native/toeffect-native/.specs/. - For Effect SQL integration, consult
.refs/effect/packages/sql/and.refs/effect/packages/sql-sqlite-bun/.
- Zig: compare
- Ensure every gap has exactly one owning task card:
- Create/adjust
.tasks/backlog/TASK-*.mdas needed. - Consume
.tasks/triage/until inbox zero:- If a triage item is valid/real, move it into
.tasks/backlog/(or.tasks/active/if you are immediately executing it). - If a triage item is obsolete/duplicate, move it to
.tasks/done/with a short explanation.
- If a triage item is valid/real, move it into
- Create/adjust
- Make links impossible to miss:
research/zig-cr/92-gap-backlog.mdunchecked items link to their task cards.- Task cards link back to their parent docs/specs.
- Mark TS work correctly:
- If TS-heavy work is not past the spec gates, mark it blocked and point at the owning
effect-native/.specs/*.
- If TS-heavy work is not past the spec gates, mark it blocked and point at the owning
Output:
research/zig-cr/92-gap-backlog.mdstays current..tasks/backlog/is a curated, non-overlapping set of next assignments.
Primary goal: unblock the 0.16.300-preview release by executing release-blocker tasks.
Meaning: take a curated subset of .tasks/backlog/ and run multiple subagents in parallel.
This workflow must produce an evergreen handoff for the adversarial "Update tasks" phase:
- Gap backlog (
research/zig-cr/92-gap-backlog.md) is update→delegate. - Delegate handoff log (
.tasks/DELEGATE_WORK_HANDOFF.md) is delegate→update.
Procedure:
- Read
.tasks/backlog/TASK-209-release-0.16.300-preview.mdfirst (release blockers). - Then read
research/zig-cr/92-gap-backlog.md(task map + historical context). - Pick tasks with disjoint
Files to Modify. - For each selected task:
- Move
.tasks/backlog/TASK-*.md→.tasks/active/TASK-*.md. - Launch one subagent with the task card as the entire prompt.
- Instruct it to only touch listed files and to update the task card as it goes.
- Move
- When complete:
- Move
.tasks/active/→.tasks/done/. - Ensure completion notes include date + commit hash.
- Refresh
research/zig-cr/92-gap-backlog.mdlinks/status.
- Move
- Commit all changes before handoff (mandatory):
- Commit in
effect-native/submodule first (if changes exist there). - Then commit in the root repo (including the submodule pointer update).
- Use descriptive commit messages referencing the task card(s).
- Record the commit hashes in the task cards' Completion Notes.
- Commit in
- Write the round outcome to the evergreen handoff log:
- Append a new "Round" section to
.tasks/DELEGATE_WORK_HANDOFF.md. - Include (at minimum):
- which task cards were executed
- commit hashes produced (if any)
- exact commands used to run tests / typecheck / lint
- the captured outputs (paste) for those commands
- coverage outputs/paths (if applicable)
- steps to reproduce the results from a clean checkout
- If no tests were run, explicitly say so (this is a red flag).
- Append a new "Round" section to
Note: .tasks/active/ can be changing while you read it. Take a snapshot and proceed.
Do not run the Zig extension inside a sqlite3 wrapper that preloads another cr-sqlite extension. Load the Zig extension explicitly into a clean sqlite process.
The nix run github:subtleGradient/sqlite-cr wrapper preloads the Rust/C cr-sqlite extension. Use it carefully:
ALLOWED:
- Use sqlite-cr as the Rust/C oracle for parity tests (reference implementation)
- In the same test script, use clean
nix run nixpkgs#sqlite+.load $ZIG_EXTfor Zig
FORBIDDEN:
- Using sqlite-cr to test Zig extension behavior (double-loading causes conflicts)
- Loading Zig extension into a sqlite-cr process
# Rust/C oracle (option A: explicit .load)
run_rust() {
nix run nixpkgs#sqlite -- "$db" -cmd ".load $RUST_EXT" "$sql"
}
# Rust/C oracle (option B: sqlite-cr wrapper - for convenience)
run_rust() {
nix run github:subtleGradient/sqlite-cr -- "$db" <<< "$sql"
}
# Zig extension (ALWAYS clean sqlite + explicit .load)
run_zig() {
nix run nixpkgs#sqlite -- "$db" -cmd ".load $ZIG_EXT" "$sql"
}- Two cr-sqlite extensions in one process = undefined behavior
- Function conflicts (both register
crsql_as_crr, etc.) - Double triggers on CRR tables
- Invalid test results
Use .tmp/ for all temporary files, never /tmp/.
This keeps temp files within the repo (gitignored) for easier debugging and cleanup.