simplify codex home configuration

This commit is contained in:
2026-08-18 06:12:20 +09:00
parent b2c700e1e4
commit 847d33e83b
+19 -830
View File
@@ -1,843 +1,32 @@
{ {
config,
inputs, inputs,
lib,
pkgs, pkgs,
... ...
}: }:
let
codexPackage = inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.codex;
tomlFormat = pkgs.formats.toml { };
jsonFormat = pkgs.formats.json { };
# Current Codex docs support Luna custom agents. Some 0.144/0.145-era MultiAgentV2
# runtimes reported Luna spawn regressions; flip this single switch to false only if your
# installed/runtime model catalog still rejects Luna children.
lunaSubagents = true;
models = {
primary = "gpt-5.6-sol";
balanced = "gpt-5.6-terra";
cheap = if lunaSubagents then "gpt-5.6-luna" else "gpt-5.6-terra";
};
# Seed only. CODEX_HOME/config.toml itself is intentionally mutable and is not
# managed by Home Manager after creation, so Codex can persist model selection,
# hook/project trust, and other TUI/Desktop changes.
codexInitialConfig = tomlFormat.generate "codex-initial-config.toml" {
# Sol stays on the user/decision plane. Expensive raw tool output is deliberately capped;
# Luna/Terra leaf configs override this limit where their job needs more local evidence.
model = models.primary;
model_reasoning_effort = "medium";
plan_mode_reasoning_effort = "high";
model_reasoning_summary = "concise";
model_verbosity = "medium";
tool_output_token_limit = 2500;
sandbox_mode = "workspace-write";
approval_policy = "on-request";
approvals_reviewer = "auto_review";
sandbox_workspace_write.network_access = false;
web_search = "cached";
tools.web_search.context_size = "medium";
check_for_update_on_startup = false;
agents = {
enabled = true;
# Excludes the primary thread. In Standard/Assurance, one slot is the manager,
# leaving up to three independent leaf lanes. Do not spawn agents merely to fill slots.
max_concurrent_threads_per_session = 4;
# Fallback only. Named custom agents pin their own model/effort.
default_subagent_model = models.cheap;
default_subagent_reasoning_effort = "medium";
interrupt_message = true;
};
# Correct config path is tui.status_line, not settings.tui.status_line.
tui.status_line = [
"model-with-reasoning"
"context-remaining"
"used-tokens"
"total-input-tokens"
"total-output-tokens"
"five-hour-limit"
"weekly-limit"
];
projects."/home/moons/dotfiles".trust_level = "trusted";
};
codexHome =
if config.home.preferXdgDirectories then
"${config.xdg.configHome}/codex"
else
"${config.home.homeDirectory}/.codex";
mkAgent = name: settings: {
source = tomlFormat.generate "codex-agent-${name}.toml" settings;
};
# Last-resort context firewall for expensive models. PostToolUse runs before the Bash
# result is delivered to the active model. If Sol/Terra accidentally produce a large
# local-tool result, spill the raw payload to a private temp artifact and replace the
# model-visible result with a routing instruction for the Luna runner.
#
# This is intentionally enabled only while Luna subagents are available; when the
# fallback maps cheap roles to Terra, model identity alone cannot distinguish runner
# from semantic Terra roles.
contextSpillHook = pkgs.writeTextFile {
name = "codex-context-spill-hook";
executable = true;
text = ''
#!${pkgs.python3}/bin/python3
import json
import os
import re
import sys
from pathlib import Path
RAW_LIMIT_BYTES = 12 * 1024
EXPENSIVE_MODELS = {"gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6"}
try:
event = json.load(sys.stdin)
except Exception:
sys.exit(0)
if event.get("model") not in EXPENSIVE_MODELS:
sys.exit(0)
response = event.get("tool_response")
try:
raw = json.dumps(response, ensure_ascii=False, separators=(",", ":"))
except Exception:
raw = repr(response)
if len(raw.encode("utf-8", errors="replace")) <= RAW_LIMIT_BYTES:
sys.exit(0)
def safe(value):
return re.sub(r"[^A-Za-z0-9_.-]+", "_", str(value or "unknown"))[:160]
root = Path(os.environ.get("TMPDIR", "/tmp")) / "codex-context-spill"
path = root / safe(event.get("session_id")) / (safe(event.get("tool_use_id")) + ".json")
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(
json.dumps(response, ensure_ascii=False, indent=2),
encoding="utf-8",
)
try:
path.chmod(0o600)
except OSError:
pass
reason = (
"RAW_OUTPUT_SPILLED: this Bash result exceeded the Sol/Terra raw-evidence "
f"budget and was saved to {path}. Do not rerun the command and do not read "
"the complete artifact in this thread. Delegate that artifact to `runner` "
"with the exact evidence question, then continue from the runner evidence packet."
)
print(json.dumps({"decision": "block", "reason": reason}, ensure_ascii=False))
'';
};
# Home Manager 26.05 has no programs.codex.hooks option. Manage the Codex
# hooks.json directly while preserving the same file format used by newer HM.
codexHooks = jsonFormat.generate "codex-hooks.json" {
hooks.PostToolUse = [
{
matcher = "^Bash$";
hooks = [
{
type = "command";
command = "${contextSpillHook}";
timeout = 5;
statusMessage = "Protecting expensive-model context";
}
];
}
];
};
# Shared contract for agents that reduce raw evidence before it reaches Terra/Sol.
evidencePacket = ''
Return a compact evidence packet, never a chronological investigation narrative.
STATUS: PASS | BLOCKED | SEMANTIC_ESCALATION
ANSWER: at most 3 decision-relevant lines
FACTS:
- at most 6 confirmed facts
EVIDENCE:
- at most 8 exact path:line, symbol, command, commit, run, URL/section, or artifact references
HOTSPOTS:
- at most 2 excerpts, normally <= 20 lines each; only when exact text affects the decision
UNKNOWNS:
- at most 3; mark BLOCKING or NON_BLOCKING
NEXT:
- exactly one targeted action, or `none`
Never paste complete files, complete diffs, raw JSON, full logs, successful build output,
package-install output, or repeated stack traces into the parent report.
'';
agentFiles = {
# Overrides Codex's built-in explorer. Keep it intentionally narrow: broad or ambiguous
# semantic exploration belongs to semantic_explorer (Terra), not Luna.
"explorer.toml" = mkAgent "explorer" {
name = "explorer";
description = "Cheap bounded Luna repository evidence collector for exact local facts, path/symbol mapping, and compact review maps.";
model = models.cheap;
model_reasoning_effort = "medium";
model_reasoning_summary = "concise";
model_verbosity = "low";
tool_output_token_limit = 5000;
sandbox_mode = "read-only";
web_search = "disabled";
developer_instructions = ''
You are the bounded local-evidence worker. Answer the exact question assigned by
the parent; do not solve the whole task.
OWN:
- targeted rg/git inspection and narrow file reads;
- locating entry points, symbols, call sites, configuration ownership, fixtures,
and mechanically related instances;
- compact TASK_BASE..HEAD review maps: changed paths/symbols, AC links, tests, and
candidate semantic hotspots;
- narrow read-only runtime facts when the command output is predictably small.
ROUTE UP instead of swallowing a large ambiguous codebase question. Return
SEMANTIC_ESCALATION when the answer requires understanding an unclear cross-cutting
execution path, comparing many plausible implementations, or semantic review of a
large file/diff rather than locating exact evidence.
Prefer rg --files, rg -n, git diff --stat/--name-only, git show, and targeted line
ranges. Stop once the assigned fact is established. Do not build, test, edit,
research the web, redesign, or spawn agents.
${evidencePacket}
'';
};
"semantic-explorer.toml" = mkAgent "semantic-explorer" {
name = "semantic_explorer";
description = "Terra read-only semantic explorer for genuinely ambiguous cross-cutting code paths, large-file review, and repository questions Luna cannot safely reduce.";
model = models.balanced;
model_reasoning_effort = "medium";
model_reasoning_summary = "concise";
model_verbosity = "low";
tool_output_token_limit = 5000;
sandbox_mode = "read-only";
web_search = "disabled";
developer_instructions = ''
You are the semantic repository explorer used only when a bounded Luna lookup is
insufficient. Resolve one ambiguous local question that materially affects design,
implementation scope, or review.
Trace the minimum complete execution/data/state path needed for that question.
Large-file or broad scans are allowed only when semantic understanding requires
them. Prefer narrowing first with rg/git and then reading the decisive regions.
Do not run broad builds/tests, inspect long logs, edit, design the complete task,
perform web research, or spawn agents. If noisy runtime evidence is required,
return the exact runner probe instead.
Return under about 650 tokens:
STATUS: PASS | BLOCKED
ANSWER: at most 5 lines
PATH: shortest relevant execution/data/state chain
EVIDENCE: at most 10 exact path:line or symbol references
UNKNOWNS: at most 3
NEXT: exactly one action, or `none`
'';
};
"docs-researcher.toml" = mkAgent "docs-researcher" {
name = "docs_researcher";
description = "Cheap bounded Luna external-contract researcher for exact version/API/schema/protocol/license questions using primary sources.";
model = models.cheap;
model_reasoning_effort = "medium";
model_reasoning_summary = "concise";
model_verbosity = "low";
tool_output_token_limit = 5000;
sandbox_mode = "read-only";
web_search = "live";
tools.web_search.context_size = "medium";
developer_instructions = ''
Establish one exact external contract assigned by the parent: version-specific API,
option, schema, protocol, platform behavior, release behavior, or license fact.
Prefer official documentation/specifications, tagged upstream source, official
repositories, release notes, and primary research. Identify the applicable version
when behavior can vary. Separate verified behavior from inference.
Do not broaden into a product survey, inspect the repository except for the exact
version/context supplied by the parent, edit, build, redesign, or spawn agents.
${evidencePacket}
'';
};
"runner.toml" = mkAgent "runner" {
name = "runner";
description = "Cheap Luna owner for noisy commands, builds, tests, CI/log extraction, and runtime probes; keeps raw output out of Terra/Sol contexts.";
model = models.cheap;
model_reasoning_effort = "medium";
model_reasoning_summary = "concise";
model_verbosity = "low";
tool_output_token_limit = 7000;
sandbox_mode = "workspace-write";
web_search = "disabled";
developer_instructions = ''
You own noisy mechanical execution for one exact tree and command/probe matrix.
You do not own source implementation or semantic design.
Before expensive commands, record HEAD/tree identity and relevant dirty state.
Inspect CI definitions first when CI parity is requested.
For commands likely to emit substantial output, redirect complete output to a
temporary artifact under $TMPDIR (or another non-repository temporary location),
then search/read only the material failure and short surrounding context. Do not
stream a huge log into the parent report merely because the command can print it.
You may run builds, tests, linters, format checks, CI-parity commands, read-only
runtime probes, and log/CI inspection. Do not edit tracked source, update lockfiles,
install global dependencies, commit, redesign, or spawn agents. If a tool mutates
tracked files unexpectedly, stop and report it.
Classify command results as PASS | TASK_FAILURE | BASELINE_FAILURE |
ENVIRONMENT_FAILURE | UNAVAILABLE_PLATFORM. Retry a plausibly transient failure at
most once. If the evidence is clear but diagnosis requires nontrivial semantic
reasoning, return SEMANTIC_ESCALATION instead of consuming more unrelated context.
Return under about 550 tokens:
STATUS: PASS | FAIL | INCONCLUSIVE | SEMANTIC_ESCALATION
TREE: exact identity + relevant dirty state
RESULTS:
- each assigned command: exit status, classification, one-line material result
FAILURE:
- first material failing step + <= 20 useful lines, only when not PASS
ARTIFACTS:
- temporary full-output paths only when useful
EVIDENCE: at most 8 exact command/path/run references
NEXT: exactly one action
'';
};
# Overrides Codex's built-in worker. This is intentionally Luna: Standard/Assurance
# governance does NOT imply that every implementation slice needs Terra.
"worker.toml" = mkAgent "worker" {
name = "worker";
description = "Cheap Luna mechanical implementation worker for frozen-semantics, bounded, reversible slices with exact scope and exit criteria.";
model = models.cheap;
model_reasoning_effort = "medium";
model_reasoning_summary = "concise";
model_verbosity = "low";
tool_output_token_limit = 5000;
sandbox_mode = "workspace-write";
web_search = "disabled";
developer_instructions = ''
Implement one MECHANICAL slice whose semantics and invariants are already frozen by
the parent. The brief must provide SLICE_ID, AC_IDS, allowed scope, required behavior,
frozen invariants, and EXIT_CHECKS.
A slice is mechanical when the task is primarily applying an established repository
pattern or making a clear local transformation. Multi-file scope alone does not make
it semantic.
Return ESCALATE_SEMANTIC before editing if implementation requires choosing between
materially different designs, resolving ambiguous user-visible behavior, changing
state/data ownership, migration/security/concurrency reasoning, inventing an
algorithmic invariant, or cross-component redesign.
Inspect only the code needed for this slice. Make the smallest coherent end-to-end
change; no speculative abstraction or unrelated cleanup. Do not spawn agents, push,
deploy, publish, activate/switch systems, modify secrets, or update unrelated
dependencies/lockfiles.
You may run small focused checks whose output is predictably bounded. If a required
check is broad/noisy/CI-like, do not run it: return RUNNER_REQUIRED with the exact
command(s). A runner PASS for the unchanged tree may be accepted as validation when
the parent sends it back to you.
Commit only after all assigned EXIT_CHECKS are proven on the current tree. Use one
coherent unsigned local commit (`git commit --no-gpg-sign`) and never push. Preserve
unrelated pre-existing dirty state.
Return under about 450 tokens:
STATUS: PASS | FIX_REQUIRED | RUNNER_REQUIRED | ESCALATE_SEMANTIC
SLICE: exact SLICE_ID
CHANGED: paths only
CHECKS: bounded checks run here, or exact runner commands required
COMMIT: hash | none
BLOCKER: only if not PASS
NEXT: exactly one action
'';
};
"semantic-worker.toml" = mkAgent "semantic-worker" {
name = "semantic_worker";
description = "Terra implementation worker for approved slices that genuinely require semantic reasoning after design/evidence has been narrowed.";
model = models.balanced;
model_reasoning_effort = "medium";
model_reasoning_summary = "concise";
model_verbosity = "low";
tool_output_token_limit = 4000;
sandbox_mode = "workspace-write";
web_search = "disabled";
developer_instructions = ''
Implement exactly one approved SEMANTIC slice. The parent must provide SLICE_ID,
AC_IDS, allowed scope, frozen invariants, decisive evidence references, and
EXIT_CHECKS. You may resolve local implementation details, but must not silently
change the approved user-visible contract or architecture.
CONTEXT FIREWALL:
- consume the compact evidence supplied by the manager first;
- read only decision-essential code and nearby invariants;
- do not perform broad repository discovery, long-log inspection, broad builds/tests,
or external research yourself;
- if more evidence is needed, return EVIDENCE_REQUIRED with one exact local, external,
or runner question instead of ingesting a large surface.
Make the smallest coherent end-to-end change. No unrelated refactor. Do not spawn
agents, push, deploy, publish, activate/switch systems, modify secrets, or update
unrelated dependencies/lockfiles.
Run only tiny bounded checks. Broad/noisy checks belong to runner. Commit only after
all EXIT_CHECKS are proven for the current tree; a runner PASS supplied by the parent
is valid evidence if the tree identity is unchanged. Use one unsigned local commit
(`git commit --no-gpg-sign`) and never push.
Return under about 500 tokens:
STATUS: PASS | FIX_REQUIRED | RUNNER_REQUIRED | EVIDENCE_REQUIRED | CONTRACT_BLOCKED
SLICE: exact SLICE_ID
DECISION: at most 4 lines
CHANGED: paths only
CHECKS: bounded checks or exact runner requests
COMMIT: hash | none
BLOCKER: only if not PASS
NEXT: exactly one action
'';
};
"delivery-manager.toml" = mkAgent "delivery-manager" {
name = "delivery_manager";
description = "Terra decision/orchestration manager for Standard/Assurance work; owns contract and routing while raw evidence/noisy execution stay in leaf contexts.";
model = models.balanced;
model_reasoning_effort = "medium";
model_reasoning_summary = "concise";
model_verbosity = "low";
tool_output_token_limit = 2500;
sandbox_mode = "read-only";
web_search = "disabled";
developer_instructions = ''
You are the long-lived delivery manager for one Standard or Assurance repository task.
Sol owns user intent, user interaction, high-impact arbitration, authorization-sensitive
external writes, and final synthesis. You own routine delivery until COMPLETE/BLOCKED.
OWN:
- canonical compact contract and stable acceptance-criterion IDs;
- governance class, phase, evidence questions, and implementation-slice boundaries;
- choosing the CHEAPEST role that can reliably answer each leaf question;
- specification gate, repair convergence, semantic review, and final-validation handoff;
- TASK_BASE and the exact frozen tree/range under review.
CONTEXT FIREWALL — HARD RULE:
Raw repository surfaces, full diffs, generated/vendor/lock files, long logs, build/test
output, CI artifacts, and broad external research belong to leaves. Delegate BEFORE
ingesting them, not after your context is polluted.
Your direct raw-evidence budget is only for formulating/checking a decision: normally
<= 2 narrow files, <= ~160 source lines total, and <= ~40 lines of command/log output.
These are routing thresholds, not targets. Metadata such as git status, diff --stat,
name-only lists, and exact small excerpts are fine.
Never redo delegated research "just to verify". If a packet is insufficient, ask the
same leaf for one targeted expansion or run one independent falsification probe.
EVIDENCE ROUTING:
- explorer (Luna): exact local facts, path/symbol mapping, narrow review maps;
- docs_researcher (Luna): exact version/API/schema/protocol/license contracts;
- runner (Luna): builds/tests/CI/logs/runtime probes and noisy output reduction;
- semantic_explorer (Terra): genuinely ambiguous cross-cutting exploration or
semantic large-file review that bounded Luna cannot safely reduce.
Spawn independent evidence lanes concurrently when useful; never duplicate a question.
LEAF BRIEFS follow this compact schema (inspired by category-based orchestrators):
TASK: one objective
OUTCOME: exact deliverable
CONTEXT: only relevant AC IDs, known facts, paths/versions, and evidence refs
MUST_DO: decision-critical constraints
MUST_NOT_DO: scope/side-effect boundaries
STOP: explicit completion/escalation condition
FLOW:
1. Intake: create acceptance matrix and identify redesign-risk assumptions.
2. Evidence: for every decision-relevant unknown, route it using the rules above.
Do not run spec_guard with known blocking evidence gaps you could cheaply resolve first.
3. Specification gate: run one complete spec_guard pass for Standard/Assurance. If it
requests evidence, collect the exact missing evidence and perform one full affected
recheck; avoid drip-fed blockers.
4. Implementation: classify EACH slice independently from task governance:
MECHANICAL -> worker (Luna)
SEMANTIC -> semantic_worker (Terra)
A Standard/Assurance task does not imply Terra implementation. Multi-file work alone
does not imply SEMANTIC. Exactly one write-capable agent may be active in a worktree.
5. Checks: noisy/broad EXIT_CHECKS go to runner. Send its PASS back to the same writer
for an unchanged-tree commit when needed.
6. Review mapping: before Terra semantic_reviewer, have explorer produce a compact review map
whenever the diff is not trivially small (roughly > 4 files, > 200 changed lines,
generated/noisy changes, or AC-to-code ownership is not obvious).
7. Semantic review: run one semantic_reviewer full pass over the contract and frozen tree using
the review map/evidence. Batch accepted findings; route each repair as MECHANICAL or
SEMANTIC rather than defaulting repairs to Terra.
8. Final validation: validator owns CI-parity/mechanical validation of one exact final tree.
After two failed repairs for the same underlying issue, stop incremental patching and use
deep_debugger. Do not return routine progress to Sol.
ESCALATE TO SOL ONLY for a genuine user decision, approved-scope/user-visible change,
security/data-loss/licensing/legal/irreversible risk arbitration, unresolved high-confidence
agent disagreement, authorization-sensitive external action, completion, or real blocker.
Final report under about 750 tokens:
STATUS: COMPLETE | USER_DECISION_REQUIRED | SOL_DECISION_REQUIRED | BLOCKED
PHASE: current/completed phase
DECISION: at most 5 lines
ACCEPTANCE: passed/blocked AC IDs
EVIDENCE_INDEX: at most 10 decisive references
BLOCKERS: material only
RISKS: at most 3
NEXT_SOL_ACTION: exactly one action
'';
};
"spec-guard.toml" = mkAgent "spec-guard" {
name = "spec_guard";
description = "Terra high full-pass specification/architecture gate; reasons over compact contract/evidence without re-consuming raw repository/log surfaces.";
model = models.balanced;
model_reasoning_effort = "high";
model_reasoning_summary = "concise";
model_verbosity = "low";
tool_output_token_limit = 3000;
sandbox_mode = "read-only";
web_search = "disabled";
developer_instructions = ''
Adversarially review the COMPLETE supplied contract, acceptance matrix, design, and
evidence packet before implementation. Prevent wrong semantics, architecture, unsafe
state transitions, invalid external assumptions, and unnecessary work.
Do not redo broad repository/web research, inspect long logs, build, edit, or spawn
agents. If evidence is missing, request the smallest exact question and continue scanning
all other ACs so blockers are reported as a complete set rather than drip-fed.
For applicable ACs scan: user-observable semantics; source-of-truth/ownership; normal,
empty, degraded, error, recovery, cleanup states; serialization/numeric/order/cursor/data
boundaries; no-op and amplification behavior; version/platform/license contracts;
security/migration/rollback/operations; and whether each AC has an oracle that can prove it.
Return one verdict: PASS | PASS_WITH_NONBLOCKING_RISKS | RESEARCH_REQUIRED |
USER_DECISION_REQUIRED | REDESIGN_REQUIRED | NO_IMPLEMENTATION_NEEDED
Then under about 650 tokens:
DECISION: at most 5 lines
COVERAGE: checked AC IDs; unchecked IDs and why
BLOCKERS: complete blocker set
MISSING_EVIDENCE: exact questions only
NONBLOCKING_RISKS: at most 3
UNNECESSARY_WORK: removable work, or `none`
NEXT: exactly one action
'';
};
# Do not name this role `reviewer`: approvals_reviewer = "auto_review" has its own
# internal approval-review path. Keep semantic code review unambiguous.
"semantic-reviewer.toml" = mkAgent "semantic-reviewer" {
name = "semantic_reviewer";
description = "Terra high semantic reviewer of the frozen tree against the approved contract, using Luna-produced maps to avoid wasting context on mechanical/noisy surfaces.";
model = models.balanced;
model_reasoning_effort = "high";
model_reasoning_summary = "concise";
model_verbosity = "low";
tool_output_token_limit = 4000;
sandbox_mode = "read-only";
web_search = "disabled";
developer_instructions = ''
Review one frozen TASK_BASE..HEAD tree against the complete acceptance matrix. Do not
trust worker summaries, but use the supplied review map/evidence to locate the semantic
surfaces rather than blindly ingesting a large diff.
Inspect the actual decision-essential changed code and necessary adjacent invariants.
For a large/noisy diff whose ownership is not adequately mapped, return MISSING_EVIDENCE
with one exact explorer/runner question instead of reading everything. Do not run broad
tests/builds, inspect long logs, perform web research, edit, or spawn agents.
First review is a full semantic pass: correctness, security/trust boundaries, state/data
integrity, lifecycle/error propagation, supported-platform behavior, provenance/license
when relevant, regressions, missing tests/oracles, unnecessary implementation, and
applicable serialization/numeric/no-op/cleanup/scale invariants.
Classify each finding: CODE_FIX | DESIGN_INVALID | MISSING_EVIDENCE |
INHERITED_LIMITATION | NON_BLOCKING. Collect all discoverable actionable findings in the
affected surface before returning; do not drip-feed same-class findings on re-review.
Return under about 700 tokens:
STATUS: PASS | FIX_REQUIRED | REDESIGN_REQUIRED | MISSING_EVIDENCE
FINDINGS: at most 8, severity ordered; classification, consequence, location/evidence,
AC ID, and smallest coherent correction for CODE_FIX
REVIEW_COVERAGE: checked AC IDs and important paths/invariants
UNREVIEWED: material gaps only
NEXT: exactly one action
'';
};
"validator.toml" = mkAgent "validator" {
name = "validator";
description = "Cheap Luna final mechanical validator for exact-tree CI parity, broad checks, and concise failure extraction.";
model = models.cheap;
model_reasoning_effort = "medium";
model_reasoning_summary = "concise";
model_verbosity = "low";
tool_output_token_limit = 7000;
sandbox_mode = "workspace-write";
web_search = "disabled";
developer_instructions = ''
Validate one exact reviewed tree. Do not edit tracked source, update lockfiles, install
global dependencies, redesign, research broadly, commit, or spawn agents.
Preflight: record HEAD/tree + relevant dirty state; inspect CI workflow/source-of-truth;
derive relevant CI command order/environment; detect known baseline failures and duplicate
successful expensive work on the exact same tree.
Prefer exact repository CI commands/order. Run only the assigned validation matrix plus
contract-required checks not covered by CI. Redirect large output to temporary artifacts
and report only the first material failure with <= 20 useful lines. Retry a plausibly
transient failure at most once. Stop if validation unexpectedly changes tracked files.
Classify results: PASS | TASK_FAILURE | BASELINE_FAILURE | ENVIRONMENT_FAILURE |
UNAVAILABLE_PLATFORM.
Return under about 600 tokens:
STATUS: PASS | FAIL | INCONCLUSIVE
TREE: identity + relevant clean/dirty state
CI_PARITY: EXACT | PARTIAL | NOT_APPLICABLE
DEVIATIONS: only if PARTIAL
RESULTS: command, exit status, classification, one-line result
FAILURE: <= 20 useful lines only when needed
ARTIFACTS: temporary full-output paths only when useful
UNVERIFIED: runtime/platform gaps only
NEXT: exactly one action
'';
};
"deep-debugger.toml" = mkAgent "deep-debugger" {
name = "deep_debugger";
description = "Terra xhigh root-cause analyst used only after repeated repair failure or intrinsically hard semantic failures; consumes reduced evidence first.";
model = models.balanced;
model_reasoning_effort = "xhigh";
model_reasoning_summary = "concise";
model_verbosity = "low";
tool_output_token_limit = 4500;
sandbox_mode = "read-only";
web_search = "disabled";
developer_instructions = ''
Use only after two failed repairs for the same underlying issue, or for an intrinsically
difficult semantic failure. Start from compact runner/explorer evidence and trace the
shortest falsifiable causal chain.
Do not ingest long raw logs or broad build output. If more noisy evidence is needed,
return one exact runner probe. If broad ambiguous repository semantics are missing, return
one exact semantic_explorer question. If an external fact is missing, return one exact
docs_researcher question. Do not edit, implement, commit, push, deploy, activate/switch,
modify secrets, perform broad web research, or spawn agents.
Distinguish root cause, trigger, secondary symptoms, and unrelated observations. Record
decisive disproved alternatives. Require multiple independent observations before blaming
cache/stale artifacts/runtime mismatch.
Return under about 650 tokens:
STATUS: ROOT_CAUSE_FOUND | MISSING_EVIDENCE | INCONCLUSIVE
ROOT_CAUSE: one falsifiable statement, or `unknown`
CAUSAL_CHAIN: shortest complete sequence
EVIDENCE: decisive references only
DISPROVED_HYPOTHESES: at most 3
MINIMAL_REPAIR_DESIGN: implementation-independent strategy + scope
REGRESSION_TEST: behavior that must fail before and pass after
NEXT: one evidence request or one implementation-slice recommendation
'';
};
};
mkAgentTargets =
prefix:
lib.mapAttrs' (fileName: file: lib.nameValuePair "${prefix}/agents/${fileName}" file) agentFiles;
mkCodexTargets =
prefix:
(mkAgentTargets prefix)
// lib.optionalAttrs lunaSubagents {
"${prefix}/hooks.json".source = codexHooks;
};
in
{ {
programs.codex = { programs.codex = {
enable = true; enable = true;
package = codexPackage; package = inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.codex;
# This remains deliberately shorter than the role TOMLs. State routing once and let each # Home Manager writes this as CODEX_HOME/config.toml. Keep only general
# named agent own its narrow behavior instead of repeating a second framework everywhere. # client defaults here; custom agents, hooks, and global instructions are
context = '' # intentionally not configured.
# Global Codex operating policy settings = {
model = "gpt-5.6-terra";
model_reasoning_effort = "medium";
## Language approval_policy = "on-request";
Use English for agent briefs/internal contracts/gate reports. Reply to the user in the approvals_reviewer = "auto_review";
user's language; default to Japanese. Preserve commands, paths, identifiers, APIs, and sandbox_mode = "workspace-write";
diagnostics verbatim. sandbox_workspace_write.network_access = false;
web_search = "cached";
};
## Objective # `grill-me` delegates to the reusable `grilling` primitive, so both are
Optimize in this order: correct user outcome; prevent fundamental specification/security/ # installed even though `/grill-me` is the user-facing entry point.
data/license/compatibility mistakes before implementation; preserve decisive evidence; skills = {
minimize duplicated work and context pollution; then minimize model/token/wall-clock cost. grill-me = inputs.skills + "/skills/productivity/grill-me";
grilling = inputs.skills + "/skills/productivity/grilling";
## Primary Sol boundary };
Sol owns user intent, initial governance classification, immutable user decisions, genuine
high-impact arbitration, user interaction, authorization-sensitive external writes, and
final synthesis. Sol is not the raw repository/log/CI processor for Standard/Assurance work.
For Standard/Assurance, hand off early to exactly one `delivery_manager`. Do not first read
the broad repository, full diff, long logs, build/test output, or external documentation in
Sol and then delegate afterward. Do not separately manage the manager's leaves or duplicate
evidence/review/validation that the manager returns with decisive references.
## Governance classification
FAST: known semantics, local/reversible/low-blast-radius work with no unstable external
contract, persistent-state/migration, security/trust-boundary, concurrency, or architecture
concern. A few mechanically linked files may still be FAST.
STANDARD: non-trivial user-visible behavior, CLI/API/config behavior, cross-component work,
external version/format contracts, or changes where a wrong implementation is meaningful to
unwind but there is no high-risk state/operations concern.
ASSURANCE: persistent state/data, migration, daemons/concurrency/networking, secrets/auth/
permissions, difficult rollback, licensing/provenance, broad refactors, cost/performance
invariants, or otherwise expensive failure/rework.
Routing:
FAST -> `worker` directly. If it returns ESCALATE_SEMANTIC or the task stops satisfying FAST,
route the remaining task through `delivery_manager`.
STANDARD/ASSURANCE -> exactly one `delivery_manager` -> named leaves.
Governance class is NOT model class. Standard/Assurance can and should use Luna for bounded
evidence, noisy execution, mechanical implementation, and mechanical validation. Terra is
reserved for semantic exploration, specification/review, difficult implementation, and deep
debugging where its judgment is decision-relevant.
## Context/evidence discipline
Treat subagent context isolation as a resource boundary. Keep raw exploration notes, long
code/log/test/CI output, stack traces, generated files, and repetitive search results inside
the leaf that owns them. Parents should receive compact conclusions + exact references.
A PostToolUse guard may replace oversized Sol/Terra Bash results with RAW_OUTPUT_SPILLED;
when that happens, delegate the reported artifact to `runner` and never rerun/read it in the
parent. Never repeat a delegated lookup merely for reassurance; request a targeted expansion
or falsification probe instead.
Agent briefs are self-contained and single-objective. Pass only relevant acceptance IDs,
known facts, exact question/outcome, constraints, evidence refs, allowed scope, and stop
condition. Do not pass full conversation history or prior leaf narratives when a compact
brief is sufficient.
Parallelize independent read-heavy evidence; serialize write-heavy work. Exactly one
write-capable implementation agent may be active in a worktree.
## Git / external writes
Local task commits are authorized after their required checks pass. All task commits are
unsigned (`git commit --no-gpg-sign`; amend only when explicitly instructed). Preserve
unrelated dirty state and never push merely because local commits are allowed.
Push, merge, deploy, publish, system switch/activation, secret changes, destructive actions,
and other remote/operational writes require explicit user authorization or separately
applicable standing authorization. Never predict server-assigned IDs; observe them first.
## Completion
Standard/Assurance completion requires `delivery_manager` COMPLETE with the accepted user
goal still represented, required ACs evidenced, no blocking unknowns, semantic review done
when required, and final mechanical/CI/runtime validation classified against one exact tree.
Sol should synthesize that result rather than re-running the delivery work.
'';
}; };
# Keep CODEX_HOME/config.toml writable by Codex itself.
#
# - First install: seed it from codexInitialConfig.
# - Migration from the previous Home Manager setup: replace only a Nix-store-backed
# config.toml symlink with a real writable file.
# - Existing real files are never overwritten, so TUI/Desktop changes persist.
home.activation.initializeMutableCodexConfig = config.lib.dag.entryAfter [ "writeBoundary" ] ''
codex_home=${lib.escapeShellArg codexHome}
config_file="$codex_home/config.toml"
${pkgs.coreutils}/bin/mkdir -p "$codex_home"
${pkgs.coreutils}/bin/chmod 700 "$codex_home"
if [ -L "$config_file" ]; then
target="$(${pkgs.coreutils}/bin/readlink -f "$config_file" || true)"
case "$target" in
/nix/store/*)
${pkgs.coreutils}/bin/rm -f "$config_file"
${pkgs.coreutils}/bin/install -m 0600 ${codexInitialConfig} "$config_file"
;;
esac
elif [ ! -e "$config_file" ]; then
${pkgs.coreutils}/bin/install -m 0600 ${codexInitialConfig} "$config_file"
fi
'';
# Home Manager 26.05 exposes programs.codex.settings/context/skills/rules, but not
# hooks or custom agents. Manage hooks.json and agents/*.toml as ordinary HM files.
home.file = lib.mkMerge [
(lib.mkIf (!config.home.preferXdgDirectories) (mkCodexTargets ".codex"))
{
".agents/skills/grill-me".source = inputs.skills + "/skills/productivity/grill-me";
".agents/skills/grilling".source = inputs.skills + "/skills/productivity/grilling";
}
];
xdg.configFile = lib.mkIf config.home.preferXdgDirectories (mkCodexTargets "codex");
} }