Files
Panama/user/agents/skills/codebase-design/DEEPENING.md
T
Gabriel Brown 89761a7da3 Keep the personal half of the desktop in one place, and ask before installing it
Agent instructions, skills, SSH host aliases and expansion triggers are worth
having identical on every machine one person owns, and belong in none of the
shared configuration. They live in user/ now, with a manifest saying where each
piece goes and a link-user stage that puts it there.

That stage does nothing unless the machine said yes. Somebody who clones Panama
to try the desktop keeps their own ~/.claude/CLAUDE.md exactly where it was;
the question names the destinations and defaults to no. Anything displaced goes
to config/old rather than being deleted.

~/.claude/CLAUDE.md and ~/.codex/AGENTS.md were byte-identical copies of one
file, which is the drift this exists to prevent.

Also adds the vitals toggles for the battery and Claude usage readouts, which
had preferences and no way to reach them.
2026-08-22 08:54:43 -04:00

2.8 KiB

Deepening

How to deepen a cluster of shallow modules safely, given its dependencies. Assumes the vocabulary in SKILL.md: module, interface, seam, adapter.

Dependency categories

Classify a candidate's dependencies before deepening it. The category decides how the deepened module is tested across its seam.

Category What it is How it is tested
In-process Pure computation, in-memory state, no I/O Merge the modules, test through the new interface directly. No adapter needed.
Local-substitutable Has a local stand-in (PGLite for Postgres, an in-memory filesystem, a framework's own local test backend) Deepenable once the stand-in exists. The stand-in runs in the test suite; the seam stays internal, with no port at the external interface.
Remote but owned Your own services across a network boundary Define a port at the seam. The deep module owns the logic; the transport is an injected adapter. In-memory adapter in tests, HTTP/RPC/queue adapter in production.
True external Third-party services you do not control The module takes the dependency as an injected port; tests supply a mock adapter.

Where the categories usually land in this stack: pure TypeScript logic is in-process; a database with a local runner is local-substitutable; Convex functions called across the network from a Next.js client are remote-but-owned; Jira, Infisical, Stripe, and similar are true external. Confirm what local test harness a framework actually ships before assuming one exists.

The recommendation for a remote-but-owned dependency reads: "Define a port at the seam, implement an HTTP adapter for production and an in-memory adapter for testing, so the logic sits in one deep module even though it is deployed across a network."

Seam discipline

  • One adapter means a hypothetical seam. Two adapters means a real one. Do not introduce a port unless at least two adapters are justified, typically production plus test. A single-adapter seam is indirection wearing a design's clothes.
  • Internal seams are not external seams. A deep module may have internal seams, private to its implementation and used by its own tests. Do not expose one through the interface merely because a test reaches for it.

Testing strategy: replace, do not layer

  • Old unit tests on the shallow modules become waste once tests exist at the deepened module's interface. Delete them; leaving both is how a suite doubles in size while covering the same behaviour twice.
  • Write the new tests at the deepened module's interface. The interface is the test surface.
  • Assert on observable outcomes through the interface, never on internal state.
  • A test that must change when the implementation changes is testing past the interface. That is the tell, and the fix is the test, not the module.