-
Notifications
You must be signed in to change notification settings - Fork 0
CONVENTIONS
Analysis Date: 2026-08-15
-
Linter: ruff
>=0.16, configured inpyproject.toml[tool.ruff] -
Formatter: none — formatting is deliberately NOT enforced. Layout is hand-tuned; do not run
ruff format. Only correctness and security rules are enabled. -
Line length: 100 (ruff
line-length = 100) -
Target version:
py312— the floor ofrequires-python, not the newest interpreter. Do not use 3.13-only constructs.
# pyproject.toml [tool.ruff.lint]
select = ["E9", "F", "B", "S", "PLE", "RUF", "BLE"]
ignore = [
"S603", # subprocess without shell=True — intentional throughout
"S607", # partial executable path — PATH resolution is by design
]assert is allowed in tests (tests/** ignores S101). The S rules replace bandit — no separate bandit dependency. BLE is active so existing # noqa: BLE001 markers stay meaningful.
Use from __future__ import annotations at the top of every module. This is universal across all source files:
# src/harnessed/launcher.py, src/harnessed/schema.py, src/harnessed/paths.py …
from __future__ import annotations-
Type checker: pyright,
typeCheckingMode = "basic", configured inpyproject.toml[tool.pyright] -
pythonVersion = "3.12"matches the ruff floor -
include = ["src", "tests", "tools"];exclude = ["src/harnessed/catalog"](container scripts) - Target: 84 pyright errors across all 128 included files. Do not widen this.
Use @dataclass (stdlib) with field(default_factory=…) for structured data. Pydantic is not in the dependency list.
# src/harnessed/schema.py
@dataclass
class McpServer:
name: str
command: str | None = None
args: list[str] = field(default_factory=list)
transport: str = "stdio"
url: str | None = None
env: dict = field(default_factory=dict)-
Modules:
snake_case.py(e.g.,hosthome.py,credmounts.py,launchenv.py) -
Functions:
snake_case. Public API uses descriptive verbs (load_stack,find_in_catalog). Internal helpers are prefixed with_(_load_yaml,_resolve_dir,_bounded). -
Classes:
PascalCase(SchemaError,McpServer,LaunchSpec,_WarnCountingConsole). Private classes may use leading_. -
Constants:
UPPER_SNAKE_CASE(CONTAINER_HOME,USERNS_ARG,HARNESS_CONFIG_DIR) -
Module-private: prefix with
_. Double-underscore is not used.
Define custom exceptions that extend Exception, not built-ins. Provide a one-line docstring explaining what condition the exception represents:
# src/harnessed/schema.py
class SchemaError(Exception):
"""A recipe/stack manifest is missing a required field or is malformed."""
class RecipeLintError(SchemaError):
"""A recipe uses raw npm/npx instead of the pnpm equivalent (BLD-03 supply-chain lint)."""
class PinValidationError(SchemaError):
"""A recipe Dockerfile contains a floating ref (--branch main/master, :latest, @latest)."""# src/harnessed/paths.py
class HomeNotFoundError(RuntimeError):
"""harnessed's catalog could not be located — see `harnessed_home`."""Raise SchemaError subclasses from parsers and validators. Let them propagate to the CLI layer (launcher.py), which prints a one-line rejection and exits.
Use the two process-wide rich.Console instances from src/harnessed/console.py. Never construct a Console in any other module.
# src/harnessed/console.py
_out = _WarnCountingConsole()
_err = _WarnCountingConsole(stderr=True)Import at the module level in callers:
from .console import _err, _outBoth consoles count warnings automatically via _WarnCountingConsole.print. rich.markup.escape is used when interpolating untrusted strings into markup. There is no logging module usage — all user-facing output goes through _out/_err.
All subprocess calls go through helpers in src/harnessed/proc.py: _run, _bounded, _say. Never call subprocess.run directly from business logic.
The project drives podman, git, mise, and other host binaries as subprocesses; S603/S607 are suppressed project-wide for this reason. PATH resolution of binaries is intentional.
Imports follow PEP 8 grouping (stdlib → third-party → local), then intra-package relative imports:
# src/harnessed/schema.py
import hashlib # stdlib
import json
import re
from dataclasses import dataclass, field
from pathlib import Path
from ruamel.yaml import YAML # third-party
from ruamel.yaml.error import MarkedYAMLError
from . import paths # intra-package relativeFor large modules (launcher.py), intra-package imports may be deferred into function bodies to avoid circular imports or to keep a module's import footprint small.
Every module starts with a docstring explaining its single responsibility, what it does NOT do, and which design decisions it embodies:
# src/harnessed/console.py
"""The two process-wide Consoles harnessed's CLI prints through.
They live here rather than in `launcher` so that a module extracted OUT of launcher can report an
error on the SAME console instance instead of constructing a second one. …
"""# src/harnessed/schema.py
"""Parse + validate recipe.yaml / stack.yaml into typed objects.
EMIT-ONLY assembler component: this module only reads files and builds in-memory
objects. It never invokes podman/docker and never writes anything. …
"""Inline comments are verbose and explain the WHY, including issue/bead IDs as historical provenance (e.g., # bd harnessed-rv2.1). These IDs reference retired tracker entries and are breadcrumbs, not active links. Comments frequently describe what WOULD go wrong if the pattern changed, making them self-documenting for reviewers.
All host-side and container-side path resolution is centralised in src/harnessed/paths.py. No caller computes profile dirs, instance names, or container paths independently. Always use paths.harnessed_home() as the anchor — never the CWD.
-
pnpm, never rawnpm/npx(pnpm dlxreplacesnpx). Enforced by theRecipeLintErrorlint. -
uvxfor light Python MCP servers. - Every download must be pinned — no
@latest,--branch main. Validated byPinValidationError. - Python toolchain managed by
mise(mise.toml). Always usemise exec -- uv …;uvis not on PATH directly.
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)