Gitwami

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:

  1. Rewind & fork agent runs
  2. Agents that don't start amnesiac (warm filesystem + semantic memory)
  3. Reactive auto-review (event-driven behaviors)
  4. Per-line AI provenance (already shipped)
  5. 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) → validates
  • draftPromptPullRequestJob (:108) → the row template
  • launchPromptPullRequestJob (:151) → cuts a compare branch from sourceBranch, opens a Draft PR, createRecords the prompt_pull_request_jobs row (: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 copies prompt/mode/baseBranch from a source job and sets sourceBranch to the prior run's compareBranch/commitSha (rewind = fork off the prior result, not base). Feed it through the unchanged launchPromptPullRequestJob (:151). Stage 3 implements this branch-only path with forkPromptPullRequestJob and ForkPromptPullRequestRunAction.
  • Schema: add forked_from_job_id UUID (nullable, self-ref) to prompt_pull_request_jobs (Application/Schema.sql:774) via a forward-only migration. In the graph (plan Phase 1) this is a derived_from edge 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 the SandboxBackend interface — see nixos-sandbox-fleet-plan.md §4–5. Hook: the provision call inside runOnLocalRunner (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/or promptRunnerEnvironmentVariables (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 → enqueuePullRequestWorkflowRuns
    • enqueuePullRequestReviewJob (: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:146Application/CommitAiContexts.hs:199storeCommitAiContextBatch: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.toml gains [agent.<key>] sections mirroring [workflow.*]: name, description, model, mode, instructions (inline) or instructions_file (path to markdown in the repo, e.g. .gitoku/agents/reviewer.md), and optional events / branches / paths for triggers.
  • A GitokuAgent type beside GitokuWorkflow (Workflows.hs:143), parsed by an added parseAgentManifest reusing the TOML validation infra (validateWorkflowManifest:706).
  • loadAgentManifestForBranch parallel to loadWorkflowManifestForBranch:209; the markdown body is read with the same loadRepositoryFileAtBranch: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 just Generic / WorkflowImport) so a run can name an agent, and add agent_key TEXT to prompt_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 via promptRunnerEnvironmentVariables (Run.hs:963). The run executes via local-runner on the NixOS host — the config is backend-agnostic, so it moves to the microVM fleet later unchanged (see nixos-sandbox-fleet-plan.md).

Graph + reactive wiring.

  • Each agent is an agent node (ActiveGraph plan §3); its runs are produced_by edges, so an agent accrues its own lineage and per-agent semantic memory (feature §2 scoped to the agent node).
  • An agent's events/branches declarations are behavior configs: the Phase-2 dispatcher (the syncRepositoryWorkflowTriggers:71-96 replacement, §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

  • GitokuAgent type, the agent_key column, and the agent→prompt composition step.

Smallest first PRs

  1. Behavior registry (§3): swap the syncRepositoryWorkflowTriggers body for a dispatcher; register the existing four enqueues. No behavior change, but the reactive substrate is now generic.
  2. Provenance → graph dual-write (§4): emit evidence node + derived_from edge at Run.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.