This is a public, read-only report. Striff reads this repository's docs, turns each sentence that makes a claim about the code into a rule, and checks the rule against the code on the default branch. How this works
agentic-pi ≥ 0.2.11 exposes githubApiBaseUrl; Last Light threads it ExecutorConfig.githubApiBaseUrl → agenticRun.
ExecutorConfig has githubApiBaseUrl
Holds
Read Oct 11
LASTLIGHT_SANDBOX=kubernetes runs each workflow phase as its own bare Pod in a dedicated namespace — the harness itself is a Kubernetes client (@kubernetes/client-node), a structural peer of the docker/smol backends behind the same Sandbox port, driven by KubernetesSandbox (src/sandbox/k8s/kubernetes-sandbox.ts).
KubernetesSandbox implements Sandbox
Holds
Read Oct 11
For PR-diff workflows the pre-clone therefore threads the PR's baseBranch (GitSandboxAccess.baseBranch, from ctx.baseBranch) through and ensureBaseAvailable (src/sandbox/index.ts) fetches the base as a real origin/<base> ref and deepens both refs (base + the depth-1 head) until they share a merge-base — depth 50 → 500 → full unshallow.
GitSandboxAccess has baseBranch
Holds
Read Oct 11
Normalize, Both transports feed the same onMessageEvent / onAppMention handlers → MessagingConnector.handleIncomingMessage() Slack-specific mention stripping via stripBotMention() Session info (channel id, thread id, platform user id) goes into envelope.raw , not into top-level fields
MessagingConnector has a handleIncomingMessage method
Holds
Read Oct 11
post-review, survey-units and any other app-specific type are dispatched through a Map<string, PhaseTypeHandler> injected on EnginePorts.handlers (phase-executor.ts, registered in runner.ts) — which is the seam to extend when a deployment needs a step the engine should not know about.
2 rules from this sentence
EnginePorts has handlers
checks “injected on EnginePorts.handlers”
Holds
EnginePorts depends on PhaseTypeHandler
checks “post-review, survey-units and any other app-specific type are dispatched through a Map<string, PhaseTypeHandler> injected on EnginePorts.handlers (phase-executor.ts, registered in runner.ts)”
Holds
Read Oct 11
Iteration naming — built by PhaseRef.format() and resolved by phaseIndexInDefinition (both in src/workflows/phase-ref.ts):
PhaseRef has a format method
Holds
Read Oct 11
WorkflowRunStore exposes addTerminalObserver, notified wherever a run is finished — simple.ts, resume.ts, the queued-run TTL expiry and the admin cancel — so a projection installed once covers all of them and a ninth terminal path cannot be added without one.
WorkflowRunStore has addTerminalObserver
Holds
Read Oct 11
RunnerCallbacks.postComment resolves to the created GitHub comment id (void on Slack, or when the post failed), and simple.ts stashes it at scratch.queuedAck.commentId.
RunnerCallbacks has postComment
Holds
Read Oct 11
The queued?: boolean on WorkflowResult propagates up through dispatchWorkflow and the dispatcher: queued runs suppress the spurious "completed" reply, leave an in-progress PR check untouched (the terminal review comment lands once admission runs the workflow), and are cancellable like any live run.
WorkflowResult has queued
Holds
Read Oct 11
Field cwd, Meaning Agent's working directory
ExecutorConfig has a cwd field
Holds
Read Oct 11
Field model, Meaning Provider/model — e.g anthropic/claude-sonnet-5-5
ExecutorConfig has a model field
Holds
Read Oct 11
Field variant, Meaning Reasoning effort — off
ExecutorConfig has a variant field
Holds
Read Oct 11
Field sandbox, Meaning Backend — gondolin (default) / docker / smol / none / kubernetes
ExecutorConfig has a sandbox field
Holds
Read Oct 11
Field sessionsDir, Meaning Where the JSONL event log lands
ExecutorConfig has a sessionsDir field
Holds
Read Oct 11
Field unrestrictedEgress, Meaning Opt out of the strict allowlist
ExecutorConfig has an unrestrictedEgress field
Holds
Read Oct 11
Field webSearch, Meaning Enable agentic-pi's web tools for this phase
ExecutorConfig has a webSearch field
Holds
Read Oct 11
Field webSearchProvider, Meaning Force a specific provider (Tavily / Brave / Exa)
ExecutorConfig has a webSearchProvider field
Holds
Read Oct 11
Field agentContextDir, Meaning Legacy — a single agent-context/ directory Accepted for call-site compatibility and ignored by loadAgentContext , which resolves layer-wise
ExecutorConfig has an agentContextDir field
Holds
Read Oct 11
Field agentContext, Meaning The run's already-composed AGENTS.md body Set by the runner when a repo layer applies used verbatim by every delivery path (issue #180 — see "Agent context" below)
ExecutorConfig has an agentContext field
Holds
Read Oct 11
ExecutionResult (profiles.ts) returns success, output, turns, error, durationMs, sessionId, costUsd, token counts, stopReason, and — where the backend can measure it — the sandbox's cpuSeconds / peakMemoryBytes / memoryLimitBytes (see "Resource usage").
Five backends, all behind the Sandbox port (src/sandbox/sandbox.ts): provision / stageSkills / runAgent / runCommand / dispose. The sandboxFor(backend, opts) factory returns DockerSandbox, SmolSandbox, InProcessSandbox (mode: gondolin | none, so it covers two backends), KubernetesSandbox, or the test-only FakeSandbox.
KubernetesSandbox is a thin orchestrator: it wires the collaborators that own the real work — WorkspaceProvisioner (PVC vs emptyDir), RunSecrets (creds/prompt Secret lifecycle), EgressEnsurer (the CiliumNetworkPolicy pair), and the free functions in pod-lifecycle.ts (wait/stream/reap) — behind the same provision / stageSkills / runAgent / runCommand / dispose shape every other backend implements.
3 rules from this sentence
KubernetesSandbox depends on WorkspaceProvisioner
checks “it wires the collaborators that own the real work — WorkspaceProvisioner”
Holds
KubernetesSandbox depends on RunSecrets
checks “it wires the collaborators that own the real work”
Holds
KubernetesSandbox depends on EgressEnsurer
checks “it wires the collaborators that own the real work”
Holds
Read Oct 11
The set reaches an adapter as intent only, the same seam EgressPolicy uses (SandboxFactoryOpts.services).
SandboxFactoryOpts has services
Holds
Read Oct 11
The orchestrator reads Sandbox.usage() inside withSandbox, before dispose().
Sandbox has an usage method
Holds
Read Oct 11
The fan-out records it once, on its own <phase>_sandbox row (PhaseRef.sandbox), and the branch rows carry none — an even split would imply a precision the cgroup does not have.
PhaseRef has sandbox
Holds
Read Oct 11
So InProcessSandbox.runAgent treats process.env as read-only and passes everything per-run as an explicit agenticRun() argument:
InProcessSandbox has runAgent
Holds
Read Oct 11
ApprovalStore.listForWorkflow(runId) returns every approval for a run (all statuses, oldest first), exposed as GET /admin/api/workflow-runs/:id/approvals.
ApprovalStore has a listForWorkflow method
Holds
Read Oct 11
Keyed on the cron, only its own fires count — which is what makes CronRunStore.recentFailures a sound input to the scheduler's consecutive-failure alert (issue #327).
CronRunStore has recentFailures
Holds
Read Oct 11
Both reads (latestByCron, recentFailures) tie-break on id, so ordering does not depend on started_at being distinct.
CronRunStore has latestByCron
Holds
Read Oct 11
All generated labels are built by PhaseRef.format() (phase-ref.ts) — the single authority — and parsed back via PhaseRef.parse() (base + kind).
2 rules from this sentence
PhaseRef has a format method
checks “PhaseRef.format()”
Holds
PhaseRef has a parse method
checks “PhaseRef.parse()”
Holds
Read Oct 11
This is driven by recreateFromBase on GitSandboxAccess / PrePopulateSpec (set in gitSandboxAccessForWorkflow).
2 rules from this sentence
GitSandboxAccess has recreateFromBase
checks “recreateFromBase on GitSandboxAccess”
Holds
PrePopulateSpec has recreateFromBase
checks “recreateFromBase on”
Holds
Read Oct 11
PhaseExecutor already depends only on PhaseReporter (not ../notify).
PhaseExecutor depends on PhaseReporter
Holds
54 rules from 8 docs
See these where the change is. The browser extension puts a pull request's doc findings, and a diagram of what it changed, on the GitHub page itself, so the code and what your docs say about it are side by side.