| name | genesis-development |
| description | This skill should be used when developing, debugging, refactoring, or building Genesis itself — tasks like "fix this in Genesis", "add a new MCP tool", "wire up the runtime", "Genesis won't start", "create a worktree", "debug the bridge", or "add a capability". Applies to any task modifying files under src/, .claude/, or tests/. Do NOT load for Genesis-as-tool work ("summarize this", "write a LinkedIn post", "research X") or general questions unrelated to Genesis internals.
|
| consumer | cc_foreground |
| phase | 10 |
| skill_type | workflow |
Load Gate
Before reading any reference, confirm the task is Genesis-development,
not Genesis-as-tool. If uncertain, ask the user: "Are we modifying
Genesis itself, or using Genesis for something else?"
On-Load Mindset
Internalize these immediately when this skill fires — they shape how to
work from the start, not just what to check before commit.
Wiring Discipline
Every new component needs at least one call site in the actual runtime
path. Apply this 4-level verification taxonomy:
- Exists — file/function present. Proves nothing.
- Substantive — tests pass, handles happy + error. No runtime proof.
- Wired — live call site, import chain unbroken. Minimum for "done."
- Data-Flow Verified — real data flows end-to-end. Required for
critical paths.
Mark nothing "done" below Level 3.
GROUNDWORK Code Is NOT Dead Code
Code tagged # GROUNDWORK(feature-id): why is intentional future
investment. Never delete or refactor it as dead code. Only remove when
the feature is fully active or the user explicitly cancels it.
Architecture Review
For medium-to-large Genesis work (3+ files, new components, wiring
changes), dispatch a genesis-architect subagent before implementation
to check dependencies, edge cases, and DRY violations. Small targeted
changes skip this.
Timeout Policy
The burden of proof is on you to justify why a timeout should exist.
Do not default to "add a timeout for safety." Instead:
- Identify the specific failure mode. What hangs? Why? Is there
evidence this actually happens, or is it speculative?
- Justify the specific value. Why this number and not another?
What legitimate work would be killed at a lower value?
- If you have no strong justification for a specific value, default
to 2 hours (7200s). This is the project floor — generous enough to
never interfere with legitimate work while preventing permanent
resource lockout from truly hung processes.
- Surface the request to the user with the value, the failure mode,
and the evidence. Never add a timeout as a "small improvement" or
"defense in depth."
Timeouts on reflections, CC calls, cognitive paths, and long-thinking
work fight Genesis instead of helping it — they cap legitimate long
thinking and add speculative defense against rare hangs. The exception
is raw subprocess calls with no external watchdog (e.g., deterministic
executor steps), where a hung process blocks shared resources (executor
semaphore) with no other recovery mechanism.
Verify Outcomes, Not Just Tests
ruff check . && pytest -v is the minimum bar, not the finish line.
After tests pass, verify the actual end-to-end outcome the change
delivers. Diff behavior between main and your changes when relevant.
For wiring changes: verify the init/bootstrap order passes the right
values at runtime, not just that parameters exist. For notification
changes: verify the notification actually arrives. Ask: "If the system
restarts right now, will this actually work?" If you can't answer yes
with evidence, you're not done.
Instance-Fix vs Class-Fix Gate
When a mechanism failed to write or propagate something (a memory, a
directive, a config row, a status flag), hand-writing the missing
artifact is a data repair — it mitigates ONE instance on ONE
install. It is never the fix. Before reporting anything as "fixed",
classify it:
- Data repair — you wrote the artifact the mechanism should have
written. Label it "data repair" explicitly, and in the same session
either fix the mechanism or get the user's explicit deferral
(recorded as a follow-up). Never report a data repair as "fixed".
- Class fix — you changed the mechanism so the artifact is written
correctly on every install, going forward, with a test proving it.
The test: "If a fresh install hits the same situation tomorrow, does my
change help them?" If the answer is no, you have repaired data, not
fixed anything. (Origin: 2026-07-17 — a stale-decision recurrence was
"fixed" with a hand-written memory + directive; the propagation
mechanism that failed to write them stayed broken.)
Code Intelligence — pick the right lane
Serena (Python LSP) is always live — it parses current files per query, so
it's the default for symbol/reference/impact questions ("who calls X", "what
breaks if I change Z") and never goes stale. CBM gives the architecture/graph
overview. GitNexus does what neither can — multi-hop blast radius, execution
flows, route/tool maps, coupling/community analysis — but it is snapshot-
based: its answers are only correct when the index matches the working tree,
and it drifts after you pull merged PRs (its reindex fires on local commit, not
on pull). So reach for GitNexus deliberately for its unique views, and run
gitnexus analyze first when freshness matters; for live "who calls this"
during active editing, prefer Serena. There is no "always run impact before
every edit" mandate — that just gates work behind a tool that's stale-by-design.
- Blast radius / impact: Serena
find_referencing_symbols (live) for the
direct caller set; GitNexus impact <symbol> (reindex first) for multi-hop +
affected processes/risk. Use the full UID if ambiguous
(Method:path/file.py:Class.method#N).
- Unfamiliar code:
gitnexus context <symbol> or browse
gitnexus://repo/GENesis-AGI/processes (when fresh).
- Custom questions:
gitnexus cypher — LadybugDB uses CodeRelation with a
type property for edges, not Neo4j-style named edge labels.
Full syntax and Cypher examples: .claude/docs/code-intelligence-guide.md;
tool-selection decision matrix: .claude/docs/code-intelligence.md
Common Traps
- Ego sessions are ACTIVE.
src/genesis/ego/ is live (v3.0a11).
Two egos: user ego (CEO, Opus) and Genesis ego (COO, Sonnet). Both
run on adaptive cadence via the awareness loop. Changes here are
production changes.
- DB path confusion.
genesis.db is at ~/genesis/data/genesis.db,
NOT ~/genesis/genesis.db. Use genesis.env.genesis_db_path().
- Column names. Use
db_schema MCP before assuming column names.
The DB has 60+ tables.
- Signal collectors. Phase 1 built stubs; Phase 6 replaced some with
real implementations. Code that looks complete may not produce signals.
- Capabilities manifest.
~/.genesis/capabilities.json is write-once
at bootstrap, not dynamic. New capabilities need registration in
_CAPABILITY_DESCRIPTIONS in src/genesis/runtime/_capabilities.py
AND a bootstrap init step.
- APScheduler IntervalTrigger resets on restart.
IntervalTrigger
counts from server startup, not from last successful run. If the
server restarts more frequently than the interval, the job never
fires. Use CronTrigger for anything longer than a few hours.
Bit us with user_model_evolution (48h interval, daily restarts).
- Silent skips are banned (provision-or-surface). A setup/resilience
feature that gracefully skips on a missing prerequisite (a package, a
host knob) must either PROVISION the prerequisite (bootstrap.sh /
host-setup.sh / a guardian reconciler) or register an effective-fact in
infra_profile that the awareness posture check
(awareness/loop.py::_check_infra_protection_posture) reads — so an
unprotected box raises a standing alert instead of staying silent. A
graceful skip with neither = a box that runs unprotected with zero
signal (a sibling install ran weeks without swap/systemd-oomd until a
memory spike wedged it, 2026-07). Guardrail:
tests/test_awareness/test_infra_protection_posture.py.
- Modules are NEVER subsystems. A capability module
(
src/genesis/modules/**, an external pluggable capability — "hands,
not brain", see modules/base.py) is not an internal Genesis
subsystem (memory, reflection, ego, triage, autonomy, sentinel).
Module memory writes must never set a source_subsystem value —
that tag means "internal decisional output, exclude from default
recall", which is wrong for module output. This is enforced
mechanically: any .store() under modules/** passing
source_subsystem is a hard CI failure in
tests/test_memory/test_store_subsystem_coverage.py, which also forces
every new memory-writer to either tag itself or be explicitly
classified as user-context. _KNOWN_SUBSYSTEMS
(memory/retrieval.py) is the authoritative subsystem list; adding a
module name to it is a category error.
- Destructive data migrations must reconcile cross-store mirror fields.
When a cleanup/backfill deletes data in one store (e.g. Qdrant vectors) but
another store mirrors that data's existence (e.g.
memory_metadata.embedding_status), the delete MUST also fix the mirror
field. A deleted vector left as embedding_status='embedded' is a field
that lies, and that lie is not cosmetic if any code path reads it —
MemoryStore._mark_superseded gates an update_payload on
embedding_status != 'fts5_only' and would fire a doomed write on the
now-deleted point. Before assuming a stale field is harmless, grep for its
reads, not just its writes. (Bit us in the source_subsystem purge, #918;
fixed by #921 Step 2c — reconcile tagged rows to fts5_only.)
immutable=1 reads miss WAL-resident writes. A read-only sqlite3
connection opened with file:...?immutable=1 reads only the main db file
and ignores the -wal, so a change you JUST committed (still
un-checkpointed) is invisible — you get a false-negative "the write
didn't land." To verify a live write, use ?mode=ro (WAL-aware) or query
through the server/CRUD path; reserve immutable=1 for historical
read-only sampling where a little staleness is fine. (A reconcile UPDATE
read clean under mode=ro but appeared unchanged under immutable=1.)
Iterative-Refinement Discipline
AI refinement cycles degrade code they were asked to "improve" — validation
gets stripped, types relaxed, function scope widened. Published measurements
show vague improvement prompts degrade security fastest across iterations.
Three binding rules:
- Iterate with scoped, explicit prompts ("fix the race in X by
serializing on Y"), never "improve/clean up/make robust".
- Be security-explicit when touching validation, auth, or boundaries —
state what must not be weakened.
- Diff each refinement for what it REMOVED (constraints, guards, type
enforcement), not just what it added.
Full failure-mode taxonomy + ordered audit passes: references/ai-code-audit.md.
Anti-Rationalization
These are excuses sessions use to skip discipline. If you catch yourself
thinking any of these, STOP — you are rationalizing a shortcut.
| Rationalization | Why it's wrong |
|---|
| "This is just a simple fix, no tests needed" | Simple fixes break complex systems. The Qdrant regression was a "simple fix." Write the test. |
| "I already know what this function does" | You haven't read the implementation. Docstrings lie. Read the actual code. |
| "Tests pass, so we're done" | Tests verify what they cover, not the outcome. Verify actual end-to-end behavior. |
| "I'll clean this up in the next commit" | Next commit never comes in autonomous sessions. Do it now or create a follow-up. |
| "This file is too large to read fully" | Read the relevant section. Partial reads lead to partial understanding and wrong fixes. |
| "The linter is happy, ship it" | Linters catch syntax, not logic. Clean lint with broken behavior is worse than a warning with correct behavior. |
| "This change is low-risk, no impact analysis needed" | Your confidence is based on what you know; checking callers reveals what you don't. Serena find_referencing_symbols is live — run it. For multi-hop blast radius, gitnexus analyze then impact. |
| "I can skip the worktree, I'll be quick" | Concurrent session safety exists because "quick" commits have destroyed work before. Always worktree. |
| "The error is transient, retry will fix it" | Diagnose first. Retrying a misdiagnosed error wastes tokens and masks root causes. |
| "I'll add the follow-up later" | Follow-ups not created in-session are lost. Create it now while context is fresh. |
| "I don't need a skill for this" | If a skill exists, use it. The using-superpowers Red Flags table exists for this exact rationalization. |
| "I can read the summary instead of the source" | Summaries lose context. If you're about to change code, read the code, not the description of it. |
| "The missing data was the problem — I wrote it, so it's fixed" | The mechanism that failed to write it is the problem. Hand-written artifacts are data repair, not a fix (see Instance-Fix vs Class-Fix Gate). |
Code Discovery
Use the right tool for how you're exploring:
- Architecture overview — CBM
get_architecture(aspects=["overview"])
- Finding symbols — CBM
search_graph(name_pattern="...") or Serena find_symbol
- Call tracing — CBM
trace_path(function_name="...") or Serena find_referencing_symbols
- Impact / blast radius — Serena
find_referencing_symbols (live caller set); GitNexus impact (reindex first) for multi-hop + affected processes
- Config/doc/non-code files — Grep/Read directly
Full decision matrix: .claude/docs/code-intelligence.md
Auditing Existing Capabilities — enumerate, don't spot-check
Before claiming Genesis "lacks X", "needs to add X", or is "weaker than
at X" — or before any competitive/architecture comparison —
verify by ENUMERATION, not a spot-check. Auditing a symbol is not auditing the
stack, and a negative from a positive search is not evidence of absence:
- Enumerate the subsystem's full module inventory before concluding anything is absent.
- Trace the call graph BOTH directions — mechanisms often live in the
wrapper/caller layer, not the first symbol (CRAG lives in the MCP recall
wrapper, not
retrieval.py; the reranker is applied by the caller).
- Grep by CONCEPT with several synonyms, not one symbol.
- Verify built/enabled/disabled against RUNTIME state (env gates, server logs),
not code presence.
- Multi-path systems → coverage matrix (N entry points × M mechanisms); hot
auto-fired paths often carry a thinner stack than the deep path — a gradient,
not an absence.
- Confidence is capped by enumeration completeness.
A 2026-06-30 competitive audit wrongly claimed Genesis lacked CRAG,
scope-before-rank, and a live reranker — all three had already shipped. Full
protocol: procedure codebase_audit / CC memory audit-enumerate-not-spotcheck.
For "does Genesis already have X", consult the subsystem map
(docs/architecture/CURRENT.md, via the subsystem-map skill) FIRST;
references/codebase-map.md stays the package-level structural companion.
Adaptive Review Protocol
Choose the review level proportional to the change:
| Change type | Review level | Examples |
|---|
| Docs / text / comments | None | Markdown prose, inline comments |
| Simple mechanical | None | Variable rename, typo fix, import reorder |
| Small focused fix | Code-reviewer agent inline | Single-function bug fix, config tweak |
| Substantial change | Code-reviewer inline + /review | Multi-file refactor, new MCP tool, wiring |
| Prompt / LLM behavior | Both + extra scrutiny | System prompts, skill instructions, routing |
Decision criteria when ambiguous: "If the change could break a runtime
path not covered by its own unit test, it needs /review. If it only
touches things with clear, isolated test coverage, code-reviewer inline
is sufficient."
The enforcement hooks (review_enforcement_prompt.py,
review_enforcement_commit.py) still fire on every change — they are
safety nets, not the decision-maker. This protocol provides the
judgment framework.
Two protocol steps apply to every review at "Code-reviewer inline" level or
above (full definitions in .claude/agents/genesis-architect.md):
- Scope-drift check first: compare stated intent (plan file / PR
description / commit messages) against
git diff --stat vs the merge-base,
and open the review with the Scope Check: CLEAN / DRIFT DETECTED / REQUIREMENTS MISSING + Intent/Delivered block. Informational, never
blocking.
- Completion status last: every review (and every skill workflow that
concludes work) ends with exactly one of DONE / DONE_WITH_CONCERNS /
BLOCKED / NEEDS_CONTEXT — with concerns listed, or blocker + what was
tried, or exactly what context is missing. Findings use the
BLOCKER / SHOULD-FIX / NOTE severity ladder with per-finding confidence
and the pre-emit quote gate (a finding must quote its motivating
file:line or be confidence-capped).
Pre-Commit Gate
Verify before any commit:
git diff --cached --stat — every file in the diff belongs to your work
git status --short — check untracked files (should be staged or ignored)
- Review level applied matches the adaptive protocol above
- Staged files do not include secrets (
secrets.env, .env, credentials)
- Private-data scan before every push (public repo). Grep the ENTIRE diff
(
git diff origin/main...HEAD) for private/identifying data — real names,
company/product names, emails, IPs, private career/project specifics, verbatim
user messages. Check ALL surfaces, not just prose: source comments,
docstrings, and test fixtures/data are the easy misses. Use a synthetic
stand-in in tests, never the real private artifact. (2026-07-01: a verbatim
private DM leaked via a test docstring + a code comment after the commit
message and PR body were already clean.)
- GROUNDWORK-tagged code not accidentally deleted
- New capabilities registered in
_capabilities.py + bootstrap manifest
- Conventional commit prefixes:
feat:, fix:, refactor:, docs:,
test:, chore:. Scope optional: feat(ego): add cadence manager.
Subject line under 72 characters. Dominant category wins if mixed.
- NEVER push to main or merge into main without a PR and user approval.
Enforced by PreToolUse hook.
- Targeted tests during development. Run ONLY the relevant test file(s)
for your changes. NEVER run the full test suite locally — CI handles that.
Check CI via
gh pr checks. Bare pytest without a file path is banned.
- Commit continuously: after every logical unit of work. Uncommitted = lost.
- PR closes a ledger item → cite
Ledger: <item-id> in the PR body (the
32-hex session_ledger row id, own line, e.g. Ledger: 71337fab…). The
repo-pulse worker auto-absorbs the row with PR evidence at the next session
boundary — deterministic, reversible via session_ledger_update. A bare id
mention WITHOUT the Ledger: marker is context, not completion (the pulse
only proposes it). Find ids via session_charter or the charter injection
block.
Generalizability Gate — build for ANY install, not this one
Genesis is a public, cloneable system. Every change must work on ANY user's
install, not just the machine it was written on. Standing user directive.
Hardware/scale adaptivity. Other installs have different RAM, disk, CPU
count, and workload scale. Never hardcode absolute resource numbers or scale
assumptions:
- Memory/disk caps: percentage-of-available or config-derived, never fixed
GB (precedent: #1029 percentage-based memory caps). Concurrency: derive
from
os.cpu_count()/config, never a literal core count.
- Hard minimums are allowed but must be EXPLICIT (documented in install
docs/config comments), not implicit assumptions that fail mysteriously.
- Workload scale varies (PR velocity, table sizes, transcript sizes):
enumerate with pagination/bounds and LOUD truncation markers, never
silent caps (precedent: repo-pulse
limit_hit).
- Optional dependencies AND optional infrastructure (Ollama, GPU,
individual API keys, a host VM/guardian, Tailscale, voice/edge hardware)
must degrade gracefully behind detection/config — presence is never
assumed (precedent: Ollama-optional,
API_KEY_VOYAGE-gated reranker,
guardian features no-op without guardian_remote.yaml).
No install-specific values in code. IPs, hostnames, usernames, absolute
/home/<user> paths, GitHub slugs, timezones: these belong in generated
local config (~/.genesis/config/genesis.yaml, written by
setup-local-config.sh) or config overlays — never in committed code,
defaults, or tests. Resolve repo paths via genesis.env.repo_root() /
genesis_db_path() (GENESIS_REPO_ROOT-aware); resolve GitHub slugs LIVE
(gh repo view --json nameWithOwner) — a configured slug can name a
real-but-wrong repo and return plausible stale data. Shipped config defaults
must work on a fresh install with ZERO overlay.
Deploy-path answer required — "how does this reach other installs?"
Every PR must have an answer for both an EXISTING install and a FRESH clone.
Merged-but-undeployable-elsewhere is a bug. The standard paths:
| Change type | Deploy path |
|---|
| Runtime code | git pull + server restart (update.sh does both) |
| DB schema | additive idempotent migration — applies at restart |
| One-off data fix / backfill | data-migration framework (post-boot, idempotent) — NEVER a hand-run script only this install executed |
| Config default | repo config file (+ optional local overlay); works with no overlay |
| systemd unit / timer | registered in bootstrap.sh AND the update path — never hand-systemctl enabled only here |
| Hooks / MCP servers | land at next CC session start (note the mid-window in the PR) |
| Guardian / host VM | update.sh redeploy (Host-Deploy Gate below) |
When a change CANNOT deploy through the standard paths (one-time host
action: packages, sudoers, cgroup settings, firmware), it must ship one of:
(a) a gated self-heal that reconciles on a recurring tick (precedent: the
guardian's swap reconcile — checks every tick, repairs config + live state,
opt-out flag), or (b) an explicit, documented operator step in CHANGELOG +
install docs. Silent "works here because I hand-fixed it" divergence is the
failure mode this gate exists to kill — it bites hardest on guardian/host
changes.
Empty-state correctness — a fresh install is state zero. Every feature
must behave correctly with NO accumulated state: empty tables, no history,
no cursor files, first run ever. First runs bound their own work
(precedent: repo-pulse lookback_days — never "all history"); readers of
possibly-absent tables degrade explicitly (precedents: dashboard
charters_available: false; charter injection byte-identical when the
migration hasn't applied yet). Test the zero state, not just the populated
one — "works here" often means "works with two years of accumulated state."
External-tool version drift. Other installs run different versions of
gh, GitNexus, Node, and Claude Code — and upgrade on their own schedule.
Never key logic on one version's observed behavior without a fallback:
prefer first-class config over output-patching, and keep the patch as a
safety net when older versions ignore the config (precedent: .gitnexusrc
- the strip job for rc-unaware versions); parse external-tool output
fail-closed against the LIVE stream, never assumed semantics; pin versions
only where the system owns the pin (
cc_version.sh + cc-align).
A settings lever for every autonomous behavior. Anything that acts
without a user in the loop — detached workers, scheduled jobs, auto-writes
— ships its operator lever in the SAME PR: a settings domain
(off | propose_only | live or equivalent) plus an env kill switch, with
invalid values degrading toward LESS write authority (precedents:
repo_pulse domain + GENESIS_REPO_PULSE_DISABLED;
session_ledger_shadow live-coerced to shadow). Another operator must be
able to turn your feature off — or cap its authority — without editing
code. This is "the user decides tradeoffs" applied to every install.
Retention for every unbounded store. Any table, log, or directory that
grows without bound ships its prune path in the SAME PR, wired into
disk_hygiene.sh or an existing retention tick (precedents: repo-pulse
45d prune; ledger-shadow 45d prune; label-aware attention-snapshot GC).
An unbounded store is a slow disk-leak on someone else's smaller disk —
retention is part of the feature, not a follow-up.
Install-agnostic tests. Tests must pass on a fresh clone with no
Genesis services, no live DB, no network, no gh auth, no local config:
synthetic fixtures only (never real usernames/slugs/IPs — doubles as the
privacy gate), injectable runners for external commands, tmp_path over
real paths, no wall-clock dependence. CI on GitHub's runners IS the
reference "different install" — anything a test can't exercise there needs
an injectable seam, not a skip-on-my-machine guard.
Host-Deploy Gate (merged ≠ deployed)
A merged PR that touches host-deployed paths is NOT done at merge. The
guardian and the host VM only pick up changes when scripts/update.sh runs —
merging and walking away leaves the host running stale code indefinitely
(observed live: a host guardian sat 3 PRs behind for a week because every
session assumed deploy "happens somehow").
Trigger paths (match = this gate applies): src/genesis/guardian/,
scripts/guardian-gateway.sh, scripts/install_guardian.sh,
scripts/host-setup.sh, scripts/update.sh, scripts/lib/cc_version.sh.
After merging such a PR, in the same session:
- Run
scripts/update.sh from ~/genesis (it redeploys the guardian when
guardian-relevant paths changed and heals host/container CC + Node pin
drift — including on a no-delta run).
- Verify the deploy landed: gateway
version op reports the expected
deployed_commit / CC version; guardian tick healthy in its journal.
- State the deploy + verification result explicitly in the wrap-up. If the
deploy cannot happen this session (host unreachable), create a follow-up
via
follow_up_create — never leave deploy as an implicit assumption.
The reverse direction is equally binding: host VMs are deploy targets,
never edit-in-place dev environments. An emergency hand-edit on a host gets a
same-day PR that lands the same change at source — a host divergence that
outlives its incident is a bug.
Pre-Merge Gate
git_push_guard.py enforces a hard gate on review findings:
- After CI passes, the merge hook automatically checks PR comments
for automated review findings (ERROR, [P1], HARD BLOCK).
- If review present with blocking findings → merge is BLOCKED
by the hook (exit code 2). Fix the findings first.
- If review present with only WARNINGs/NOTEs → merge allowed.
- If no review comments at all (quota exhausted) → merge allowed
on CI alone. Note in PR that review was quota-limited.
- Override: Append
# review-override to the merge command to
bypass the gate (e.g., gh pr merge 123 --squash --admin # review-override).
The override is logged. Use only when findings are intentionally accepted.
- Read the PR's warning comments before merging — not just the hard gate.
Beyond Codex, a structural-review bot posts under the repo-owner account
(
WingedGuardian, review state COMMENTED) and emits SOFT WARNINGs (PII /
private-text / wording) that the hook does NOT block on and that a naive
.comments scan misses. Check BOTH gh pr view N --json reviews,comments
and gh api repos/<owner>/<repo>/pulls/N/comments, and address each soft
warning or consciously accept it. Never merge past an unread warning.
- Codex findings are INLINE review comments — invisible to
gh pr view.
Codex's review body is boilerplate ("Here are some automated review
suggestions"); its actual [P1]/[P2] findings live only at
gh api repos/<slug>/pulls/N/comments. Derive <slug> live —
gh repo view --json nameWithOwner --jq .nameWithOwner — NEVER hardcode
it (configs name several repos; the working repo is not the org default).
A 404 from that endpoint means WRONG SLUG or PR number, never "no
findings" — a clean PR returns []. The merge-gate hook only blocks
ERROR/[P1]/HARD BLOCK, so unread P2s pass silently (2026-07-10: 8 real
P2s on the entity-layer PRs were merged past this exact way).
- A CONFLICTING PR silently suppresses the whole CI suite. When a PR
has a merge conflict with main, GitHub cannot build the merge ref, so
pull_request-triggered workflows (the entire ci.yml suite) never run —
while CodeQL still passes on the head SHA, making the check list LOOK
green. A thin check list (only Analyze/CodeQL) means CHECK
gh pr view N --json mergeable — CONFLICTING needs a rebase before any
CI verdict exists at all (2026-07-16: #1089 sat conflict-suppressed
through three pushes; main had moved under it via concurrent sessions).
Reference Router
Read references ONLY when relevant to the specific task. Do NOT load all
references on every trigger.
| When you need... | Read... |
|---|
| Subsystem purpose/maturity/do-not-touch (judgment layer) | docs/architecture/CURRENT.md |
| Codebase structure, package map, gotchas, debugging | references/codebase-map.md |
| Package/module/symbol navigation (progressive drill) | codebase_navigate MCP tool (L0→L1→L2) |
| venv, DB paths, Qdrant, Ollama, network, commands | references/environment.md |
| Worktree rules, concurrent sessions, branch naming | references/worktrees.md |
| tracked_task, exc_info, os.killpg, logging patterns | references/observability.md |
| V3 state, build order, GROUNDWORK, architecture docs | references/architecture.md |
| Phase 6 contribution pipeline, sanitizer | references/contribution.md |
| Pending work, active incidents, subsystem status | references/build-state.md |
| Auditing/deep-reviewing AI-generated code (failure taxonomy, audit passes) | references/ai-code-audit.md |
| Which code tool to use (CBM vs Serena vs GitNexus vs Grep) | .claude/docs/code-intelligence.md |
Freshness rule: On first read of codebase-map.md in a session,
verify structural claims against current code. If a package status or
gotcha has changed, flag to user before acting on stale assumptions.
docs/architecture/CURRENT.md carries per-entry verified: stamps
enforced by scripts/check_subsystem_map.py (CI subsystem-map-check) —
after changing a subsystem's capabilities, update its entry and stamp.
Public Repo & Release Workflow
The public repo (GENesis-AGI) is the primary development repo.
Standard open-source workflow: PRs go directly to the public repo.
- Squash merges only — merge commits are disabled on the public repo.
Always
git pull --rebase origin main after merging a PR before
committing locally, or push will be rejected (non-fast-forward).
- README is public-authoritative — the public repo's
README.md is
hand-crafted and must NEVER be overwritten.
- CHANGELOG audience is users — only include entries a user updating
their install would care about. No internal refactors, README changes,
CI tweaks, or process artifacts. Lead with the user-visible effect, not
the implementation technique.
- No sensitive data in commits — voice data, research profiles, IPs,
and secrets must never enter the repo. User data lives in overlays
outside the repo (e.g.,
~/.claude/skills/*/, ~/.genesis/).
- Individual campaigns are user data, not infrastructure — a campaign's
name/prompt/targets/cadence live only in the
campaigns DB table and the
private backups repo; never hardcode them into tracked source. Unlike modules
(which ship defaults under config/modules/*.yaml), campaigns ship ZERO
defaults (no config/campaigns/). Only campaign infrastructure ships. Express
reusable session types as generic roles (e.g. the community-responder
profile), not names coupled to a live campaign. See src/genesis/campaigns/__init__.py.
- External egress is gated; owner-facing egress is not — any autonomous send to the
outside world (Discord, Medium, Twitter/X, Slack,
DistributionManager.distribute) MUST
route through the capability shadow-gate (autonomy/shadow_gate) before the enforce stage;
the scripts/check_external_io.py CI guard backstops new endpoints. Delivery TO the owner
(Telegram/voice/email-to-owner) is NEVER gated. Full contract in autonomy/shadow_gate.py.