-
Notifications
You must be signed in to change notification settings - Fork 0
STRUCTURE
Analysis Date: 2026-07-31
The authoritative vocabulary (agent/recipe/service/stack/catalog) is in ARCHITECTURE.md at the repo root. The data-flow and key abstractions are in docs/codebase/ARCHITECTURE.md. This document covers where things live, naming conventions, and where to add new code.
harnessed/ # bare repo: .bare/ + main/ + .claude/worktrees/
├── pyproject.toml # Python project config; entry points: harnessed, harnessed-tools
├── src/
│ └── harnessed/ # the application package
│ ├── __init__.py # package version (__version__)
│ ├── launcher.py # `harnessed` CLI (Typer) — 7 000+ lines
│ ├── cli.py # `harnessed-tools` CLI (argparse) — assembler + test entrypoints
│ ├── schema.py # typed models + catalog parsing (Recipe/Stack/ServiceDef/Agent)
│ ├── assemble.py # emit-only assembler: stack + recipes → committed profile
│ ├── emit.py # file writers (mcp.json, hatago config, Dockerfile, identity)
│ ├── paths.py # single source of truth for all path resolution
│ ├── synclinks.py # LinkSyncer: fan recipe skills/commands/rules into profile
│ ├── persist.py # global persist allowlist + ownership guard
│ ├── persist_gc.py # persist dir listing + prune
│ ├── scan.py # supply-chain scan gate (osv-scanner CVSS parsing)
│ ├── capability.py # capability test: launch stack --fresh, diff oracle
│ ├── report.py # render capability test results (rich table or JSON)
│ ├── staleness.py # build-stamp detection for stale profiles
│ ├── update.py # `harnessed update`: find + bump outdated pins
│ └── catalog -> ../../catalog # symlink; packaged into wheel; real dir in checkout
│
├── catalog/ # authored content — SHIPPED INSIDE THE WHEEL
│ ├── agents/
│ │ ├── claude/agent.yaml # Claude Code harness
│ │ ├── omp/agent.yaml # OpenMachinePro harness
│ │ ├── opencode/agent.yaml
│ │ ├── antigravity/agent.yaml # agy (Gemini-derived)
│ │ └── codex/agent.yaml
│ ├── base/
│ │ ├── Dockerfile.harnessed-base # shared base image (hatago baked in-container)
│ │ ├── Dockerfile.harnessed-claude # per-harness agent layers
│ │ ├── Dockerfile.harnessed-omp
│ │ ├── Dockerfile.harnessed-opencode
│ │ ├── Dockerfile.harnessed-antigravity
│ │ ├── Dockerfile.harnessed-codex
│ │ ├── egress-firewall.sh # egress firewall script (runs in-container post-start)
│ │ ├── extra-tools.default.txt # seeded into ~/.config/harnessed/extra-tools.txt at first build
│ │ ├── harnessed-scan # in-container scan entrypoint
│ │ ├── harnessed-start # container start script (runs hatago, then waits)
│ │ └── pnpm/config.yaml # pnpm policy config baked into the base image
│ ├── recipes/
│ │ ├── <name>/ # single recipe
│ │ │ ├── recipe.yaml # manifest (required)
│ │ │ ├── Dockerfile # (optional) system-layer steps only
│ │ │ ├── install.sh # (optional) install script (both modes)
│ │ │ ├── setup.sh # (optional) setup script (runtime phase)
│ │ │ ├── skills/<skill>/ # (optional) fanned into .claude/skills/<skill>/
│ │ │ ├── commands/<cmd>/ # (optional) fanned into .claude/commands/<cmd>/
│ │ │ └── rules/<rule>/ # (optional) fanned into .claude/rules/<rule>/
│ │ └── <family>/ # recipe family (no recipe.yaml at this level)
│ │ └── <variety>/ # variety = a complete recipe dir (recipe.yaml etc.)
│ ├── recipes.backlog/ # planned recipes (not yet active; not in the catalog search path)
│ ├── services/
│ │ ├── beads-server/ # dolt sql-server (scope: project, unix socket)
│ │ ├── agentmemory/ # agentmemory MCP service (scope: global)
│ │ ├── gbrain/ # gbrain MCP service
│ │ └── ping/ # test service
│ └── stacks/
│ ├── gsd-core_repowise/ # repowise + gsd-core composition
│ ├── hostbeads/ # beads/team with host-run backend
│ ├── hostbeads_stealth/
│ ├── hostmcp/
│ ├── hostspike/
│ └── openbrain-example/
│
├── catalog-local/ # gitignored; DX symlinks → ~/.config/harnessed/catalog
│ # (never inside catalog/ — setuptools would package them)
│
├── tests/
│ ├── conftest.py # FORCE_COLOR pop (must run at module import time)
│ ├── fixtures/
│ │ ├── recipes/ # minimal recipe dirs for schema/assembly tests
│ │ ├── services/ # minimal service dirs
│ │ └── stacks/ # minimal stack dirs
│ └── test_*.py # ~75 test modules (see Key Locations below)
│
├── docs/
│ ├── codebase/ # generated maps (this file; regenerate with /map-codebase)
│ └── (wiki clone, gitignored) # docs/guides/*, docs/harnessed-design.md live only in main/
│
└── .claude/
├── worktrees/ # task worktrees (created by EnterWorktree)
├── rules/ # project-level Claude rules
└── settings.json # project Claude Code settings
| Entrypoint | File | Function |
|---|---|---|
harnessed CLI |
src/harnessed/launcher.py |
main() → app() (Typer) |
harnessed-tools CLI |
src/harnessed/cli.py |
main() |
| Command | Function | What it does |
|---|---|---|
build |
build() |
Assemble + build images + populate volumes + scan |
launch |
launch() |
Start pod, attach harness (container backend) |
host-run |
host_run() |
Materialize home, exec harness (host backend) |
test |
test_stack() |
Run capability test oracle |
new |
new_stack() |
Scaffold a new stack.yaml |
install |
install_stack() |
Install a stack from the user overlay |
uninstall |
uninstall_stack() |
Remove an installed stack |
list |
list_stacks() |
Enumerate all visible stacks |
stop |
stop() |
Stop a running instance |
rm |
remove() |
Remove a stopped instance |
prune |
prune() |
Remove all stopped instances for a stack |
clean |
clean_profiles() |
Remove emitted profile dirs |
update |
update_pins() |
Find + bump outdated pins |
scan |
scan() |
Supply-chain scan a built stack |
rescan |
rescan() |
Nightly online re-scan of all built images |
svc |
svc() |
Service management subcommands |
aws-sso |
aws_sso() |
AWS SSO ECS credential forwarding |
host-gc |
host_gc() |
Garbage-collect stale host homes |
volume-gc |
volume_gc() |
Garbage-collect orphaned named volumes |
| Function | File | Purpose |
|---|---|---|
catalog_roots() |
paths.py:140 |
Returns [user_overlay, harnessed_home/catalog]
|
find_in_catalog(kind, name) |
paths.py:173 |
Resolve a single entry across roots |
list_catalog(kind) |
paths.py:198 |
Enumerate all entries across roots (deduped) |
catalog_relpath(name) |
paths.py:154 |
Map a ref (beads/stealth) to on-disk path |
| Function | File | Purpose |
|---|---|---|
assemble() |
assemble.py:106 |
Main entry: parse → validate → emit → stamp |
_merge_servers() |
assemble.py:68 |
Collect MCP servers; collision detection |
_resolve_service_servers() |
assemble.py:84 |
Resolve service: refs → URLs |
compute_recipe_hash() |
assemble.py:50 |
Image label: SHA-256 of stack.yaml + recipe dirs |
| Function | File | Purpose |
|---|---|---|
load_stack_with_recipes() |
schema.py |
Top-level loader: stack + full recipe closure |
load_stack() |
schema.py |
Parse a single stack.yaml (with extends: resolution) |
load_recipe() |
schema.py |
Parse a single recipe.yaml
|
load_service() |
schema.py |
Parse a single service.yaml
|
load_agent() |
schema.py |
Parse a single agent.yaml
|
expected_capabilities() |
schema.py |
Build the capability test oracle |
validate_pin() |
schema.py |
Reject floating refs in Dockerfiles |
validate_no_raw_npm() |
schema.py |
Reject raw npm/npx |
| Function | File | Purpose |
|---|---|---|
reset_profile() |
emit.py:36 |
Wipe + recreate profile dir |
write_mcp_json() |
emit.py:48 |
.mcp.json → single hatago endpoint |
write_hatago_config() |
emit.py |
hatago.config.json with all recipe servers |
write_derived_dockerfile() |
emit.py |
Concatenated Dockerfile for the stack image |
write_settings_json() |
emit.py |
Floor settings.json (permissions, hooks) |
write_claude_md() |
emit.py:61 |
.claude/CLAUDE.md from stack.instructions
|
LinkSyncer.fan() |
synclinks.py |
Copy skills/commands/rules into .claude/
|
| Function | File | Purpose |
|---|---|---|
harnessed_home() |
paths.py:76 |
The dir containing catalog/ (repo root or wheel) |
profile_dir(stack, harness) |
paths.py:248 |
$XDG_DATA_HOME/harnessed/profiles/<stack>/<harness>/ |
host_home(stack, harness) |
paths.py:263 |
$XDG_DATA_HOME/harnessed/home/<stack>/<harness>/ |
instance_name(stack, harness, path) |
paths.py:313 |
harnessed-<harness>-<stack>-<hash8> |
persist_workspace_dir() |
paths.py:434 |
Per-worktree persist dir |
persist_project_dir() |
paths.py:465 |
Cross-worktree persist dir (keyed by git-common-dir) |
persist_in_repo_dir() |
paths.py:444 |
In-repo persist anchor (checkout root) |
git_common_dir() |
paths.py:349 |
git common dir for a project path |
bare_worktree_container() |
paths.py:369 |
Parent of a bare repo's git-common-dir |
| Function | Purpose |
|---|---|
_ensure_stack_volumes() |
Create + fingerprint-gate config/tools volumes; run installs |
_run_container_installs() |
Run each recipe's install.sh in a throwaway install container |
_ensure_services() |
Start global/project service containers (idempotent) |
_persist_mounts() |
Build -v args for recipe persist entries |
svc_socket_env() |
Build HARNESSED_<SVC>_SOCKET env vars for a stack |
svc_client_env() |
Build client_env vars from project-scoped services |
| Function | Purpose |
|---|---|
_launch_host() |
Orchestrate host-run launch |
_materialize_host_home() |
Fingerprint-gated profile → host_home materialization |
_host_run_installs() |
Run install.sh scripts on host filesystem |
_host_run_inits() |
Source init.run snippets; propagate exported env |
_host_run_setups() |
Run setup.sh scripts on host |
_share_host_claude_state() |
Symlink history/sessions/memories to shared store |
| File(s) | What they cover |
|---|---|
test_emit.py |
Profile file emission correctness |
test_schema.py, test_schema_thread_safety.py
|
Recipe/stack/service parsing, validation, thread safety |
test_launcher_build.py, test_launcher_install.py
|
Build pipeline (mocked podman) |
test_launcher_scan.py |
Scan gate logic |
test_launch_host.py, test_launch_parity.py
|
Host-run backend; parity between container and host |
test_install_script.py |
Install env precedence; script validation |
test_install_migration_*.py |
Migration checks for content/node/system/uv tools |
test_persist_mounts.py, test_persist_allowlist.py, test_persist_gc.py
|
Persist system |
test_project_scoped_services.py, test_service_refs.py
|
Service management |
test_folder_env_contract.py |
Folder-env variable completeness |
test_scan.py, test_scan_coverage_reporting.py
|
osv-scanner gate logic |
test_staleness.py |
Build stamp detection |
test_stack_extends.py |
Stack inheritance resolution |
test_paths.py, test_harnessed_home.py
|
Path resolution |
test_synclinks.py |
LinkSyncer collision detection + fan behavior |
test_capability_tests.py |
Capability test oracle |
test_catalog_json_schemas.py |
JSON schema validation of catalog entries |
test_wheel_packaging.py |
Wheel contains catalog; no host-local leaks |
test_update_*.py |
Pin-update logic |
- Python modules:
snake_case.py(all undersrc/harnessed/) - Catalog manifests:
recipe.yaml,stack.yaml,service.yaml,agent.yaml - Dockerfiles in
catalog/base/:Dockerfile.harnessed-<name>(base, per-harness, and derived stacks share this naming) - Recipe Dockerfiles:
Dockerfile(one per recipe dir, no suffix) - Install scripts:
install.sh - Setup scripts:
setup.sh - Test files:
test_<module_or_feature>.py
- Recipe names: lowercase kebab-case (
gsd-core,codebase-memory-mcp) - Recipe variety refs:
<family>/<variety>(beads/stealth,beads/team) - Stack names:
<recipes_joined_by_underscore>with hyphens within a recipe name (gsd-core_repowise); stack names must not match any harness name - Service names: lowercase kebab-case (
beads-server,agentmemory) - Agent/harness names: single token (
claude,omp,opencode,antigravity,codex)
- Podman instance name:
harnessed-<harness>-<stack>-<sha1[:8](project_path)>(seepaths.instance_name) - Config volume:
harnessed-cfg-<harness>-<stack> - Tools volume:
harnessed-tools-<harness>-<stack> - Service container:
harnessed-svc-<service_name>(global) orharnessed-svc-<service_name>-<project_hash>(project-scoped) - Derived image:
harnessed-<harness>-<stack>:latest - Base image:
harnessed-base:latest - Agent image:
harnessed-<harness>:latest
- Create
catalog/recipes/<name>/recipe.yaml. Minimum viable manifest:name: <name>
- Add optional files:
Dockerfile,install.sh,setup.sh,skills/,commands/,rules/. - Reference from a
stack.yaml:recipes: [<name>].
For a recipe variety: catalog/recipes/<family>/<variety>/recipe.yaml. The family dir must have no recipe.yaml of its own.
- Create
catalog/stacks/<name>/stack.yaml:name: <name> recipes: [recipe-a, recipe-b]
- Optionally use
extends: <parent-stack>to inherit another stack's content.
-
catalog/agents/<name>/agent.yaml—name:andimage:. -
catalog/base/Dockerfile.harnessed-<name>— agent-specific image layer. -
src/harnessed/launcher.py— add to_HARNESS_ATTACH_CMDdict. -
src/harnessed/schema.py— add toHARNESS_CONFIG_DIRdict. - If the harness uses a non-Claude identity format, add an
elif harness == "<name>":branch inassemble.assemble()and a writer inemit.py.
-
catalog/services/<name>/service.yaml—name:,port:,scope:,data:. -
catalog/services/<name>/Dockerfile. - Reference in a recipe via
mcp.servers[].service: <name>or in a stack viaservices: [<name>].
Add @app.command("<name>") + decorated function to src/harnessed/launcher.py for a top-level harnessed command. Add a subparser entry to _build_parser() in src/harnessed/cli.py for a harnessed-tools subcommand.
- Extend
_PERSIST_VALID_SCOPESor_PERSIST_VALID_LOCATIONSinsrc/harnessed/schema.py. - Add path resolution in
src/harnessed/paths.py(a newpersist_*_dir()function). - Add mount-building logic in
launcher._persist_mounts().
Add tests/test_<feature>.py. Fixtures shared across tests go in tests/conftest.py. Minimal fake catalog trees (recipe/stack/service dirs) go under tests/fixtures/. Podman-dependent tests are skipped unless HARNESSED_PODMAN=1 is set in the environment.
Start Here
Guides
- Recipe authoring
- Service authoring
- Stacks
- Extending stacks (proposed)
- Recipe catalog
- System prompt & rules (proposed)
- Secrets
- AWS SSO
- Pulumi (host login forwarding)
- Egress & exposing services
- Container filesystem
- Git hooks
- Troubleshooting
- Pin management (harnessed update)
Codebase Map
Planning & Roadmap
- open work: GitHub Issues
Research & Prompts
- research/ (home-folder requirements per harness, browse in-repo)
- prompts/ (reusable prompt templates, browse in-repo)