Skip to content

Latest commit

 

History

History
200 lines (156 loc) · 8.7 KB

File metadata and controls

200 lines (156 loc) · 8.7 KB

AGENTS.md

Short operating manual for AI agents working in this repo.

Invariants

These must always hold true:

  1. 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.).

  2. 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.

Pointers

  • 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/

TypeScript Work Rule

  • 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.

Task Cards (contract)

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 Modify against everything in .tasks/active/.
  • One task card = one owner = one atomic commit.
  • Use .tmp/ for temp files (never /tmp/).

Triage follow-ups (inbox)

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-*.md file 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.

Wishes

Workflow:

  1. List .wishes/*.md (not subdirs).
  2. Pull constraints/requests into planning.
  3. If satisfied, move to .wishes/done/ and append: date, what changed, commit hash.
  4. If blocked, move to .wishes/blocked/ and append the reason.

"Update tasks" (backlog refresh)

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.md as 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.
  1. 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.
  2. Snapshot the inbox + queue:
    • .wishes/*.md
    • .tasks/triage/ (triage inbox)
    • .tasks/{active,backlog,done}/
  3. Reconcile implementation vs intent:
    • Zig: compare zig/ to research/zig-cr/* (esp. 90-feature-matrix.md, 93-phased-execution-proposal.md).
    • TS: compare effect-native/packages-native/ to effect-native/.specs/.
    • For Effect SQL integration, consult .refs/effect/packages/sql/ and .refs/effect/packages/sql-sqlite-bun/.
  4. Ensure every gap has exactly one owning task card:
    • Create/adjust .tasks/backlog/TASK-*.md as 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.
  5. Make links impossible to miss:
    • research/zig-cr/92-gap-backlog.md unchecked items link to their task cards.
    • Task cards link back to their parent docs/specs.
  6. 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/*.

Output:

  • research/zig-cr/92-gap-backlog.md stays current.
  • .tasks/backlog/ is a curated, non-overlapping set of next assignments.

"Delegate work" (parallel subagents)

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:

  1. Read .tasks/backlog/TASK-209-release-0.16.300-preview.md first (release blockers).
  2. Then read research/zig-cr/92-gap-backlog.md (task map + historical context).
  3. Pick tasks with disjoint Files to Modify.
  4. 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.
  5. When complete:
    • Move .tasks/active/.tasks/done/.
    • Ensure completion notes include date + commit hash.
    • Refresh research/zig-cr/92-gap-backlog.md links/status.
  6. 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.
  7. 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).

Note: .tasks/active/ can be changing while you read it. Take a snapshot and proceed.

Zig testing (detailed policy)

Core Rule

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.

sqlite-cr Wrapper Usage

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_EXT for Zig

FORBIDDEN:

  • Using sqlite-cr to test Zig extension behavior (double-loading causes conflicts)
  • Loading Zig extension into a sqlite-cr process

Test Script Pattern

# 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"
}

Why This Matters

  • 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

Temporary Files

Use .tmp/ for all temporary files, never /tmp/.

This keeps temp files within the repo (gitignored) for easier debugging and cleanup.