-
Notifications
You must be signed in to change notification settings - Fork 0
STACK
Mike Crowe edited this page Aug 15, 2026
·
5 revisions
Analysis Date: 2026-08-15
Primary:
- Python 3.12+ — all host CLI logic under
src/harnessed/; tested against 3.12 (floor) and 3.13 in CI - Shell — container entrypoints (
catalog/base/harnessed-start,egress-firewall.sh), recipeinstall.shscripts
Secondary:
- YAML — declarative manifests for agents, recipes, services, and stacks (
catalog/**/*.yaml) - Dockerfile — container image definitions (
catalog/base/Dockerfile.harnessed-*,catalog/agents/*/,catalog/services/*/)
Host (CLI)
- Python 3.12 (floor of
requires-python = ">=3.12") - Version pinned via
mise.toml:UV_PYTHON = "3.12"; venv located per-branch at~/.local/share/harnessed/venvs/<branch>/.venv - Package manager: uv (all
uv run --extra dev …invocations;mise exec -- uv …inside containers) - Lockfile:
uv.lockcommitted at the repo root;mise.lockper-recipe for binary tools incatalog/recipes/*/
Container (image)
- Base:
ubuntu:24.04(catalog/base/Dockerfile.harnessed-base) - Runtime manager: mise (installed at image build time; shims on PATH)
- Python
3.12— mise-managed in image - Node
22LTS — mise-managed; required by pnpm@11 - pnpm
11— mise-managed; governs all npm-registry tool installs in images - Container runtime: podman (host-native, no daemon socket, no DooD)
Core CLI:
-
typer >= 0.12, < 1.0— CLI commands (harnessedandharnessed-toolsentrypoints insrc/harnessed/launcher.py,src/harnessed/cli.py) -
ruamel.yaml >= 0.18, < 0.19— round-trip YAML parsing for manifests (src/harnessed/schema.py) -
rich >= 14, < 15— terminal output, progress, and tables (src/harnessed/console.py)
Data modelling:
- Python
dataclasses(stdlib) — typed recipe/stack/agent/service objects (src/harnessed/schema.py) - No Pydantic; validation is explicit in
schema.pyviaSchemaError,PinValidationError,RecipeLintError
Testing:
-
pytest >= 8+pytest-cov— test runner; config inpyproject.toml[tool.pytest.ini_options] -
pytest-randomly >= 3— randomised test order; determinism is a requirement for count-based assertions -
hypothesis >= 6— property-based tests for invariants -
mutmut— mutation testing (paths_to_mutate = ["src/harnessed/"]); run withHARNESSED_DIR=$PWD -
diff-cover— coverage restricted to changed lines
Lint / type / static analysis:
-
ruff >= 0.16— linter (rules:E9 F B S PLE RUF BLE; formatter deliberately NOT enforced);target-version = "py312" -
pyright 1.1.411— type checker (typeCheckingMode = "basic"); installed viamiseasnpm:pyright;extraPaths = ["tests"]forimport support -
shellcheck 0.11.0— shell script linter; installed viamise -
pip-audit 2.10.1— dependency vulnerability scanning
Build:
-
setuptools >= 68— wheel build;catalog/shipped inside wheel viasrc/harnessed/catalogsymlink -
pip-audit— declared as a runtime dep so it is always available for the audit layer
Critical:
-
ruamel.yaml— all manifest parsing; round-trip mode preserves comments (important for emit-only assembler) -
typer— entire CLI surface;extend-immutable-callscoverstyper.Option/typer.Argumentin ruff config -
rich— all user-visible output formatting
Infrastructure (tools in container images):
-
mise— manages all versioned tool installs inside images;MISE_GLOBAL_CONFIG_FILEredirected to~/.local/share/mise/config.tomlso config travels with installs in the volume -
pnpm@11— all npm-registry installs in images must go through pnpm (supply-chain policy BLD-01/BLD-03);npxand barenpm install -gare linted away -
uv+osv-scanner— installed viamise use -gin base image; Python toolchain and vulnerability scanning -
osv-scanner— supply-chain scan run inside the image at build time
Extra mise-managed tools (container, catalog/base/extra-tools.default.txt):
-
bat@0.26.1,eza@0.23.5,sd@1.1.0,dua@2.41.1,gping@1.20.4— modern CLI replacements -
jq@1.8.2,jless@0.9.0,glow@2.1.2,hexyl@0.17.0,yq@4.53.3— data viewing -
lazygit@0.64.0— git TUI -
ast-grep@0.45.1,ruff@0.16.2,stylua@2.5.2,markdownlint-cli2@0.23.2— dev/code tools
Config layering (catalog resolution, searched in order):
-
~/.config/harnessed/catalog— user overlay; wins on name clash -
catalog/— repo root (shipped in wheel); default authoring surface -
$XDG_DATA_HOME/harnessed/generated/— machine-minted stacks (--recipe); included only when present
Profile output (never in repo):
-
$XDG_DATA_HOME/harnessed/profiles/<stack>/<harness>/— assembled profiles (.claude/,.mcp.json,Dockerfile.harnessed-<stack>)
Environment overrides:
-
HARNESSED_DIR— overridesharnessed_home()resolution (required formutmutruns; seepyproject.toml) -
HARNESSED_PODMAN=1— gates podman integration tests intests/conftest.py -
UV_PROJECT_ENVIRONMENT,UV_PYTHON— set bymise.tomlfor per-branch venvs
Secrets management:
- Credentials referenced, never replicated (CLAUDE.md constraint)
- 1Password CLI (
op) available in base image for SSH commit signing; socket forwarded from host when present - Credential mounts handled by
src/harnessed/credmounts.py - No
.envfiles; no hardcoded secrets in any catalog asset
Pin policy:
- Every download pinned: Dockerfile base tags, GitHub Actions to commit SHAs, mise tool versions, recipe
install.refs:blocks -
schema.PinValidationErrorrejects--branch main/master,:latest,@latestin recipe Dockerfiles at parse time -
schema.parse_extra_toolsrejects unpinnedextra-tools.txtentries before podman is invoked
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)