Skip to content

Argus Task System — Design (epic / feature / task, evidence-derived status)

Date: 2026-06-15. Status: DESIGN / pre-implementation. Captures the design discussion of 2026-06-14/15. Grounded in docs/research/2026-06-14-task-system-research.md (two deep-research runs).

NOT to be confused with docs/plans/2026-06-12-tasks-module-m3.md — that is the Python cron task-runner (heartbeat/distill/ofelia run-reporting + watchdog). THIS is the work-tracking system: epic/feature/task items whose "done" is derived from CI/merge evidence. Different concern, different tables.

All decisions from the 2026-06-14/15 design walk are folded in below and RESOLVED — Decision 3 (the multi-evidence AND rule) was confirmed 2026-06-17. Design is locked; ready for the TDD implementation plan.

Goal

A personal, agent-maintained work tracker (epic/feature/task hierarchy) where the hardest problem — keeping status trustworthy when a coding agent, not a human, is the maintainer — is solved by making terminal "done" a DERIVED consequence of tamper-resistant evidence (a merged PR + a green CI test the agent cannot edit), never an agent-asserted flag. It also records the planning discipline now codified in ~/.claude/PLANNING.md (vertical slice + acceptance criterion + one PR).

Core thesis (from the research)

Agents falsely claim completion at first-class rates (~21% of MAST multi-agent failures are verification failures) and actively game the signal they're trusted on (delete/monkey-patch tests to force green). Therefore: a test-gated status is only trustworthy if the agent CANNOT edit the oracle. The fix is a deterministic checker, outside the agent's write reach, that sets terminal status from external evidence — exactly what GitHub's merge-closes-issue and spec-kit's test-first gate operationalize.

v1 scope (minimal, in Argus)

One table, one checker, one rollup view, one read-only UI. Deliberately small.

  • items table — epic/feature/task via type + parent_id.
  • item_events — append-only audit log (every lifecycle change + verify/un-verify).
  • An evidence-checker task (deterministic; same shape as existing Argus tasks) that reads CI truth from gitea.db action_run and sets verified.
  • A rollup SQL view (parent done iff all non-optional children verified).
  • A read-only /ui/tasks page (mirrors /ui/parked).

Deferred (do NOT design now): dependency/blocks edges + ready-queue (v2), bug-as-distinct-type with regression-test gate (v3), the "discovered-scope" intake, decomposition automation, anything LLM.

The load-bearing details (RESOLVED 2026-06-15)

Expensive to retrofit; decided in the design walk.

  1. Stable human-readable ID — RESOLVED: per-project prefix. ARGUS-<n>, TURFTRACK-<n>, etc. — prefix + per-project monotonic number, embedded in branches/PR titles/commits. Schema carries a project field + a per-project counter (counters table or per-project sequence), not one global sequence.
  2. Evidence is structured AND bound — RESOLVED. {kind, repo, pr_number, commit_sha, test_or_job}, machine-checkable (not a freetext URL). Anti-gaming rule: the checker counts evidence ONLY if the PR references the item ID (else any green PR could be attached).
  3. lifecycle has no "done" — RESOLVED. Agent-writable lifecycle = backlog | ready | in_progress | blocked | cancelled. Terminal truth lives only in verified (checker-set). Keystone: if lifecycle could say "done," we're back to asserted status.
  4. Append-only item_events from day 1 — RESOLVED. Every lifecycle change + verify/un-verify, with the evidence snapshot. Trust-first; retrofitting is lossy.
  5. Required why on every item — RESOLVED (added 2026-06-15). A first-class why field (rationale/context: why this needs doing), required on epic, feature, AND task — distinct from body (the how). With acceptance (tasks) this is a two-pronged admission gate: state why it matters, and (for tasks) how it's verified — structurally blocking vague/ad-hoc items.

Evidence tiers — how non-code tasks verify (RESOLVED 2026-06-15)

verified always requires at least one piece of evidence the building agent cannot unilaterally produce. The bound kind depends on task nature; the system records WHICH tier verified it, so the trust level is always visible:

  • Tier 1 — external system (strongest): ci_run (named test green on the Forgejo runner — the real gate in the autonomous loop, since the agent merges its own PRs), pr (merged to default branch), deploy_log/healthcheck (gatus 200, Komodo deploy success) for ops tasks. Agent-independent.
  • Tier 2 — artifact exists (medium): artifact — a file/doc committed at a path; the checker verifies existence deterministically (git/fs), not quality. Artifact-only tasks must pair with a Tier-1 or Tier-3 gate.
  • Tier 3 — human approval (escape hatch): approval — a human marks it done via the UI; the agent can NEVER self-approve. For decisions, physical tasks, anything with no digital signal. Recorded in item_events (who + when). The UI needs an Approve action (reuses the parked-UI Retry pattern: HX-Request request, CSRF fence, event row).

Verification rule — RESOLVED 2026-06-17 (Decision 3): verified iff ALL bound evidence passes (AND across the evidence the task declares). No weighting — binary "all required evidence present and passing, or not done," to avoid the soft/gameable partial status the design exists to remove. A code task binds CI-green (+ PR-merged); a doc task may bind only approval; an ops task binds a healthcheck. If a PR is merged but its bound test is absent/red, the task is NOT verified. This moves authority from the agent flipping feature_list.json to the checker reading gitea.db.

Per-type contract

One record type, shared columns, but required/meaningful fields differ by type. Only tasks carry their own acceptance + evidence; epic/feature done-ness is DERIVED from children.

field epic feature task
id / type / parent_id / project yes yes (->epic) yes (->feature)
title the outcome the visible behavior the vertical slice
why (REQUIRED) why this milestone why this behavior why this slice
body scope (in/out) what behavior / detail approach / notes
acceptance derived optional integration check REQUIRED (testable criterion)
evidence derived rolls up REQUIRED at done (tiered — see above)
steps[] optional checklist (agent-maintained, NOT evidence-gated)
lifecycle derived derived agent-writable
verified rollup rollup checker-set
priority yes yes yes

Subtasks — RESOLVED 2026-06-15: NOT a durable row type. Within-task decomposition lives as an optional steps[] checklist field ON a task (the agent's plan/progress for one PR), explicitly NOT evidence-gated and NOT rolled up. Only the task's verified is load-bearing. The sharp test: would this step be its own PR with its own green test? If yes → it's a sibling task (the hierarchy handles it); if no → it's a steps[] checklist item. This keeps the trust model at the task level and avoids reintroducing agent-asserted status below it.

What each level's detail holds: - Epic = milestone contract: why (rationale) + capability + explicit scope in/out. No own acceptance; done when its features are. - Feature = one visible behavior, a vertical slice; why + the behavior. Done when its tasks verify. If small enough to be one PR, it IS a single task — don't force a split. - Task = the leaf, the only strict one: title + why + acceptance (required) + evidence + optional steps[] + verified. One task = one PR = one green check. This is feature_list.json grown up.

Worked example (dogfooding this very system)

EPIC  ARGUS-M6  "Trustworthy task system"
  body: Outcome — track epic/feature/task work where "done" is DERIVED from
        CI/merge evidence, not asserted.
        In scope: items table, evidence checker, rollup view, read UI.
        Out of scope: dependencies, bug-type, decomposition automation.
  status: 0/4 verified (rolls up)

  FEATURE  ARGUS-M6-F1  "Evidence-derived task status"
    body: A task reaches verified only when its PR is merged to main AND its
          named test is green, set by a checker outside the agent's write reach.

      TASK  ARGUS-101  "items + item_events schema"
        why:        every other field hangs off this table; ship it first so
                    the checker and rollup have something to write to.
        acceptance: migration creates items + item_events; TestItemsSchema green in CI
        evidence:   { kind: ci_run, repo: runonyourown/argus, commit: <sha>, test: TestItemsSchema }
        steps:      [ ] write failing TestItemsSchema
                    [ ] write migration  [ ] run suite green
        lifecycle:  in_progress     verified: false  (checker-set)

      TASK  ARGUS-102  "verifier reads gitea.db action_run"
        acceptance: flips verified=true ONLY when PR merged-to-main AND named
                    run=success AND the PR references the item id; TestVerifierGitea green
        lifecycle:  ready           verified: false

      TASK  ARGUS-103  "rollup SQL view (parent done iff all non-optional children verified)"
        acceptance: TestRollupView green — reverting a child PR un-dones the parent
        lifecycle:  backlog         verified: false

The tree IS the plan and the tracker: read top-down to plan; leaves are the PR-sized units; status rolls up so an epic shows 0/4 verified at a glance.

Authoring vs reading (no dual source of truth)

The DB is canonical (the checker writes verified there; queries are deterministic). What you read/plan against is a generated tree view — short by default (ARGUS-M6 0/4 · F1 0/3 · ARGUS-101 in_progress), expand a node for body/acceptance/evidence. Authoring goes through one thin interface (CLI/MCP/UI) that writes the DB; the readable TASKS.md-style tree is generated, never hand-edited — avoiding the "same status in two places" failure the research flags. This is the existing Argus pattern (DB canonical, markdown is an export).

Presentation layer — visual plan / visual recap (roadmap, fed from the DB)

The DB is the state/verification engine; the visual layer is how a human reads and approves it. Aaron wants this to be visual and approvable, not a plain text tree. Prior art studied 2026-06-15: BuilderIO/skills (MIT, npx @agent-native/skills@latest add) — two skills that are a near-match for the presentation layer we want:

  • /visual-plan — turns a plan into an interactive MDX artifact with diagrams, file maps, annotated code, open questions, UI/prototype review, "scannable, commentable, intuitive enough for a human to approve before code changes start." This is a richer form of our "generated tree view," and its approve-before-coding gate maps directly onto our Tier-3 approval evidence.
  • /visual-recap — turns a branch/PR diff into MDX with annotated diffs, diagrams, API/schema summaries, file maps, UI state, review notes; a GitHub Action auto-generates one per PR. For Argus this is the rendered form of a task's PR/CI evidence — the "what actually changed" companion to verified. (We'd wire it via a Forgejo Action.)
  • Viewer: the "Agent-Native plans app" (BuilderIO/agent-native, MIT, TS, Drizzle/Nitro — self-hostable, "any DB, any host"). But it's a full agent-native app framework (needs ANTHROPIC_API_KEY for its app features), far heavier than a plan viewer.

STEAL: the MDX section structure (diagrams / file-maps / annotated / open questions), approve-before-coding, and auto-recap-per-PR. AVOID: adopting the agent-native viewer wholesale (heavyweight, AI-key deps) — Argus's hub already serves its own HTML/UI, so render our own MDX/HTML from the DB; and their informal approval (human just reads) — we keep the structured approval evidence (recorded, who+when, agent-can't-self-approve).

Sequencing: v1 ships the engine + a simple read-only /ui/tasks. The rich visual-plan/visual-recap render is v2 presentation, generated FROM the DB (the data model already supports it). /visual-plan can also be used standalone today as a planning aid while Argus handles tracking. Distinct concern from the verification engine; does not affect Decision 3.

Tamper boundary (the most important hardening)

Terminal status is derived from CI evidence (gitea.db action_run on the Forgejo runner), NOT the agent's local go test. The checker and the verified column are writable only by the checker process, not the building agent. This is what turns the existing feature_list.json pattern from a soft prompt rule into a real gate. The agent may set lifecycle and attach evidence; it may never set verified.

Where it lives / relationships

  • Argus, not track: the CI evidence, run-store, no-show watchdog, and the agent loop already live here; bolting evidence-derived status onto Argus is less work than merging two products.
  • Complementary to the M3 cron tasks-module and to the memory hub — different concern; no shared tables.

Decisions — all RESOLVED

per-project IDs (#1), structured+bound evidence (#2), lifecycle-has-no-done (#3), append-only item_events (#4), required why, evidence tiers + approval for non-code tasks, subtasks-as-steps[]-checklist (not a row type), and the multi-evidence rule (Decision 3, confirmed 2026-06-17): verified = AND across all bound evidence. Design is locked.

Next step

Write the TDD implementation plan (migration + failing test per task) under docs/plans/, starting with ARGUS-101 (items + item_events schema), and reconcile/retire references so the M3 cron-tasks plan and this work-tracking system are clearly distinct. The visual plan/recap presentation layer is tracked as v2 (see Presentation layer).