Developer-facing features
How the developer wins — rewind/fork runs, warm and semantic memory, reactive auto-review, per-line provenance, per-repo agents — map onto the existing gitoku code.
How the five developer wins land on the existing gitoku code. Companion to
activegraph-continuity-plan.md (the
graph/event/behavior layer) and
nixos-sandbox-fleet-plan.md (isolation +
statefulness). The point of this doc: each "attractive to developers" feature is
a small, located change, not a rewrite — three of the five legs already exist
in primitive form.
The features:
- Rewind & fork agent runs
- Agents that don't start amnesiac (warm filesystem + semantic memory)
- Reactive auto-review (event-driven behaviors)
- Per-line AI provenance (already shipped)
- Per-repository agent instructions (named agents, run on the Nix machine)
All file:line anchors below were verified against the tree.
1. Rewind & fork agent runs
Developer win: an agent run is a resumable (commit, fs snapshot, trace).
Fork from the snapshot just before it broke, tweak the prompt, re-run — warm
caches intact. Or run the same task three ways and keep the best diff.
What exists today. A prompt run is created by CreatePromptPullRequestAction
(Web/Controller/PullRequests.hs:210-269; mirrors at
Web/Controller/Repositories.hs:1184, API at Web/Controller/Api.hs:993). It
builds a PromptPullRequestRequest (prompt, title, description,
baseBranch, sourceBranch; mode hardcoded Generic) and calls:
buildPromptPullRequestJob(Application/PromptPullRequests.hs:78) → validatesdraftPromptPullRequestJob(:108) → the row templatelaunchPromptPullRequestJob(:151) → cuts a compare branch fromsourceBranch, opens a Draft PR,createRecords theprompt_pull_request_jobsrow (:182-189).
So a "run" today already captures prompt, mode, baseBranch, sourceBranch,
compareBranch, commitSha, pullRequestId.
The seam.
- Fork: add a builder beside
draftPromptPullRequestJob(:108) that copiesprompt/mode/baseBranchfrom a source job and setssourceBranchto the prior run'scompareBranch/commitSha(rewind = fork off the prior result, not base). Feed it through the unchangedlaunchPromptPullRequestJob(:151). Stage 3 implements this branch-only path withforkPromptPullRequestJobandForkPromptPullRequestRunAction. - Schema: add
forked_from_job_id UUID(nullable, self-ref) toprompt_pull_request_jobs(Application/Schema.sql:774) via a forward-only migration. In the graph (plan Phase 1) this is aderived_fromedge between run nodes. - The fs side of the tuple comes from §2's snapshot work; without it, fork reuses the prompt + branch but not the warm filesystem.
Reusable: the entire launch path. New: one builder + one column (+ a
"Fork" button on the Tasks page, Web/Controller/Repositories.hs:3522
buildRepositoryTasksView).
2. Agents that don't start amnesiac
Developer win: the second run boots with deps/build cache already present (warm fs) and knows what was already tried/decided/rejected (semantic memory), so it stops re-litigating.
What exists today. Each run is stateless. In
Application/Jobs/PromptPullRequest/Run.hs:151-153 the code explicitly notes
agent results stay in the sandbox and are discarded — the user pushes a branch
back on demand (PushLocalProjectBranchAction). The runner clones fresh and
copies the tree into a throwaway workspace (Runner.hs copyWorkspaceTree).
Prompt context is assembled at renderCodexPrompt (Runner.hs:~1465) and env at
promptRunnerEnvironmentVariables (Run.hs:963).
The seam (two memories, per the plans).
- Physical memory (warm fs): capture a workspace snapshot at the success
point (§3,
Run.hs:146); on a fork/rerun, boot the sandbox from that snapshot (ZFS clone) instead of a cold clone. Implemented in theSandboxBackendinterface — seenixos-sandbox-fleet-plan.md§4–5. Hook: the provision call insiderunOnLocalRunner(Run.hs:312) /runLocalRunnerProcess(IsolatedExecution.hs:683). - Semantic memory: inject the relevant graph subgraph (prior
claims/decisions/failures for this repo/task) into the prompt at
renderCodexPrompt(Runner.hs:~1465) and/orpromptRunnerEnvironmentVariables(Run.hs:963). The subgraph is read from the graph tables (plan Phase 1).
Reusable: the prompt-render + env-injection seams are already the single choke points for "what the agent sees." New: snapshot capture/restore in the backend + a subgraph reader feeding the prompt.
3. Reactive auto-review (event-driven behaviors)
Developer win: open a PR → review fires; a dependency unblocks → next task starts; contradictory claims → flagged. No hand-orchestrated YAML.
What exists today — and it's closer than expected. There is already a single
function that is the entire bespoke "event → behavior" table:
syncRepositoryWorkflowTriggers (Application/RepositoryWorkflowTriggers.hs:71-96).
On a push it:
- enqueues branch workflow runs for each changed branch (
:77); - for each open PR whose compare branch moved →
enqueuePullRequestWorkflowRunsenqueuePullRequestReviewJob(:88-89);
- for compare- or base-branch moves →
enqueuePullRequestConflictResolutionJob(:94).
Ingress is handleRepositoryRefChanges (Application/RepositoryRefChanges.hs:60),
reached from git push (Web/Controller/Repositories.hs:2848), PR merge
(Web/Controller/PullRequests.hs:1179/1387), and prompt-job completion
(Run.hs:151). Enqueue primitives live in Application/Workflows.hs
(enqueueBranchWorkflowRuns:294, enqueuePullRequestWorkflowRuns:329,
enqueueManualWorkflowRun:433, all → createWorkflowRunRecord:1254);
enqueuePullRequestReviewJob (Application/PullRequestReviewJobs.hs:38) carries
its own gating (open + AI-reviews-enabled + dedup on (pullRequestId, commitSha)).
The seam. Replace the hardcoded body of syncRepositoryWorkflowTriggers
(:77-95) with a generic dispatcher that emits a graph_event per change and
fans out to registered behaviors keyed on (event_type, node predicate). The
four inlined enqueue* calls become the first four registered behaviors —
identical output, now data-driven. This is exactly plan Phase 2, and it's a
single function body swap plus a behavior registry.
Reusable: every enqueue* primitive and the review gating. New: the
event emit + the behavior registry/dispatcher.
4. Per-line AI provenance (already shipped)
Developer win: "show me every change AI made to this file, and why" — prompt, model, reasoning, at line level.
What exists today. Storage: commit_ai_contexts (Application/Schema.sql:746-769),
unique on (repository_id, commit_sha, capture_index), with source_family,
exact_model_name, prompt, thinking, session_id, capture_confidence,
evidence_kind, modified_files, modified_line_spans_json. Written at the
run-success point via replaceCommitAiContexts
(Application/Jobs/PromptPullRequest/Run.hs:146 →
Application/CommitAiContexts.hs:199 → storeCommitAiContextBatch:212,
delete-then-insert in one transaction).
Line resolution: loadLineAiContextAtRevision
(Application/AiContextLookup.hs:71) does a blame-like walk
(Git.lineHistoryCommitShasAtRevision), fetches contexts for those commits
(fetchCommitAiContextMap), and filters with pullRequestPromptAttributionForLine
(:111) / commitAiContextAppliesToFileLine (:129) against the stored line
spans. Surfaced via PullRequestLineAiContextAction
(Web/Controller/PullRequests.hs:285) and
Web/View/Components/CommitAiContexts.hs (commit view, PR show, diff, browser).
The seam (generalize to the graph). Each commit_ai_contexts row is an
evidence node (evidence_kind, capture_confidence, prompt/thinking payload,
session_id); its modified_line_spans_json spans are derived_from edges
from evidence → (file, line-range) at a commit. The blame walk in
loadLineAiContextAtRevision is the edge traversal a graph query would replace.
Emit the node + edge at the same insertion point as the provenance write
(Run.hs:146) so provenance and graph stay atomic.
Reusable: all of it — this is the most mature leg. New: dual-write into
graph_nodes/graph_edges at Run.hs:146.
5. Per-repository agent instructions
Developer win: leave named agents on a repo — each with its own
persona/instructions/model — and run them (on the Nix machine via local-runner
to begin with, as today). "reviewer" reviews PRs, "refactor" cleans modules, each
behaving per its versioned instructions.
Reuse the workflow-manifest pattern — it already exists. gitoku reads
repo-versioned config from gitoku.toml at a branch:
loadWorkflowManifestForBranch (Application/Workflows.hs:209) →
loadRepositoryFileAtBranch repository.repositoryStoragePath branch "gitoku.toml"
(:211), parsed into GitokuWorkflow records (:143), with an event vocabulary
(WorkflowEvent, workflowMatchesEvent:552, workflowEventCode:563) and
per-branch scoping. The live gitoku.toml already has [workflow.deploy] with
name/description/events/branches/steps. Agents are the same shape.
Data model.
gitoku.tomlgains[agent.<key>]sections mirroring[workflow.*]:name,description,model,mode,instructions(inline) orinstructions_file(path to markdown in the repo, e.g..gitoku/agents/reviewer.md), and optionalevents/branches/pathsfor triggers.- A
GitokuAgenttype besideGitokuWorkflow(Workflows.hs:143), parsed by an addedparseAgentManifestreusing the TOML validation infra (validateWorkflowManifest:706). loadAgentManifestForBranchparallel toloadWorkflowManifestForBranch:209; the markdown body is read with the sameloadRepositoryFileAtBranch:211.- Instructions are version-controlled and travel with the code — exactly "leave special instructions on the repository," and they branch/PR like code.
Execution on the Nix machine (local-runner, current backend).
- Generalize
PromptPullRequestMode(Application/PromptPullRequests.hs:44, today justGeneric/WorkflowImport) so a run can name an agent, and addagent_key TEXTtoprompt_pull_request_jobs(Schema.sql:774) recording which agent produced the run. - At launch (
launchPromptPullRequestJob:151), resolve the agent def at the target branch, select its model/mode, and compose the prompt: agent instructions + the user's task. - Inject at the existing choke points:
renderCodexPrompt(Runner.hs:~1465) prepends the agent instructions as the system preamble; the resolved instructions ride the payload viapromptRunnerEnvironmentVariables(Run.hs:963). The run executes vialocal-runneron the NixOS host — the config is backend-agnostic, so it moves to the microVM fleet later unchanged (seenixos-sandbox-fleet-plan.md).
Graph + reactive wiring.
- Each agent is an
agentnode (ActiveGraph plan §3); its runs areproduced_byedges, so an agent accrues its own lineage and per-agent semantic memory (feature §2 scoped to the agent node). - An agent's
events/branchesdeclarations are behavior configs: the Phase-2 dispatcher (thesyncRepositoryWorkflowTriggers:71-96replacement, §3 above) routes a matching repo event to the agent. That is the roadmap's "webhook endpoint + AI router prompt dispatching to agents."
Reusable: the manifest load/parse/scope path, the event-match helpers, the
whole prompt-job launch + prompt-injection seams. New: the [agent.*] schema
GitokuAgenttype, theagent_keycolumn, and the agent→prompt composition step.
Smallest first PRs
- Behavior registry (§3): swap the
syncRepositoryWorkflowTriggersbody for a dispatcher; register the existing four enqueues. No behavior change, but the reactive substrate is now generic. - Provenance → graph dual-write (§4): emit
evidencenode +derived_fromedge atRun.hs:146. Backfills the graph from the one place provenance is already written.
These are independent, each touches one well-defined seam, and together they stand up the run-fork + reactive + graph + per-repo-agent foundations the rest of the plans build on. The warm-filesystem half of §2 lands with the sandbox backend work in the fleet plan.
NixOS sandbox fleet
A forkable, stateful, NixOS-native execution layer for agent code — provisioned with nixos-anywhere, disko and Firecracker.
Fork agent run
Branch-only rewind/fork of prompt-PR agent runs — re-run off a prior result branch with forked_from_job_id lineage, ahead of warm-fs snapshot forks.