-
Notifications
You must be signed in to change notification settings - Fork 0
CONCERNS
Mike Crowe edited this page Jul 31, 2026
·
5 revisions
Analysis Date: 2026-07-31
-
Location:
src/harnessed/launcher.py - Impact: The single largest maintenance risk in the codebase. Container lifecycle, host-native launch, image build, service management, credential forwarding, MCP emit, persist, staleness, daemon-state detection, and CLI dispatch all live in one file. Merges conflict constantly; it is hard to test any slice in isolation; the backend-abstraction epic (harnessed-0tk) cannot land cleanly until the seams are extracted.
-
Fix approach: The open epic harnessed-0tk calls for extracting a backend-interface seam (0tk.1). Start there: move container-run helpers into a
_container.py, service lifecycle into_service.py, and host-native launch into_host.py.schema.py(2253 lines) is a distant second and should be reviewed for splitability once launcher is tamed.
-
Location:
src/harnessed/assemble.py:50-65 -
Impact: Editing a service's
service.yamlor Dockerfile does NOT change the stack image hash, soharnessed buildconsiders the image current and skips a rebuild. The service sidecar image will be rebuilt (it has its own build path), but derived stack image label mismatches can cause a misleading "stale" warning at the wrong time or miss a needed rebuild of an image that embeds service config. -
Fix approach: Filed as harnessed-p0t (P2). Include
catalog/services/<name>/files in the hash digest for every service referenced by the stack. Mirror therecipe.root.rglob("*")pattern already used for recipe dirs.
-
Location:
src/harnessed/launcher.py:5134 -
Impact: In the host-native launch path,
_ensure_servicesis called withmount_path=project_path(the raw project directory), not the widened mount path computed by_resolve_mount_path. For a bare + linked-worktree layout the widened path is the container of the bare repo, and services withlocation: in_reporely on the wider mount for git remote operations (bd dolt push). With the narrower path the service container cannot see sibling worktrees, causing git operations to fail silently or error. The container launch path at line 5432 passesmount_pathcorrectly; host-native does not. -
Fix approach: Filed as harnessed-wnf (P3). Compute the widened mount path before calling
_ensure_servicesin the host-native path, matching what the container launch path does.
-
Location:
src/harnessed/launcher.py(service credential handling),catalog/services/ - Impact: Filed as harnessed-1vx (P3 bug). Deleting a service secret while the sidecar is running leaves clients unable to authenticate against a server that is still healthy. There is no graceful rotation path — the only recovery is manual sidecar restart.
-
Fix approach: Either prohibit secret deletion while the service is running (with a clear error), or add a
harnessed svc restartcommand that re-seeds credentials atomically.
- Location: Filed as harnessed-8ej (P2 epic)
- Impact: Permission rules are ineffective and do not survive container restarts. This is a security-surface gap — permissions that appear to be in force may not be.
- Fix approach: Track harnessed-8ej; the fix requires durability in the per-pod permission layer.
-
Location:
src/harnessed/launcher.py:4055-4057 -
Impact: The function's docstring explicitly says identification is "by CONTENT, not by name" and that "a recipe is free to ship a directory with any name." Yet line 4055 returns
Trueimmediately ifentry.name == "daemon". A recipe that ships a directory calleddaemon/for its own purposes would be misidentified as Claude Code daemon state and silently preserved across rebuilds, stranding the recipe content. -
Fix approach: Filed as harnessed-1d3 (P3). Remove the name-shortcut; rely solely on the
_DAEMON_STATE_MARKERScontent check, which is unambiguous.
-
Location:
src/harnessed/launcher.py:2550,src/harnessed/launcher.py:2569 -
Impact: Both clauses return
Falsewithout logging. Line 2550 is in_is_user_catalog_stack(a path-resolution guard); line 2569 is inhas_token(a credential-presence check). A programming error (wrong type, AttributeError, PermissionError) would silently suppress the check, causing wrong behavior downstream — either treating a non-user-catalog stack as one, or treating a missing token as present. The BLE001-suppressed catch at line 1070 is intentional and annotated; these two are not. -
Fix approach: Narrow each to the specific exceptions that represent expected-failure conditions (
OSError,ValueError). Add at minimum a debug-level log before returningFalse.
-
Location:
src/harnessed/launcher.py:161,168,177,263,389,584,884,953,1091,1345,1351,1388,1505,1555,1592,1596,1627,1642,1661,1787,1799,2332,2366(and more — 62 total calls, majority without timeout) -
Impact:
subprocess.runwithouttimeout=hangs indefinitely if podman becomes unresponsive (e.g., during a network partition while pulling, or a runc deadlock). The process is killed only by the user or the OS.scan.py:160andcapability.pycorrectly settimeout=per call; launcher.py is inconsistent. -
Fix approach: Add an optional
timeoutkwarg to the_podmanhelper at line 448 and propagate it. Audit each call: podman write operations (rm, create, build) should have a timeout on the order of minutes; inspect/status calls should be seconds.
- Location: Filed as harnessed-kf9 (P1 bug)
- Impact: In published-port mode, restarting the beads-server sidecar pins live agent sessions to the old unix socket reference, causing them to lose access to the beads service without any error surfaced to the user.
- Fix approach: Track harnessed-kf9; root cause and fix are still under investigation.
- Location: Filed as harnessed-9hp.3 (P2 bug)
- Impact: The guard that detects token presence in an env-file may silently remount the credential file even when it should not. A missed guard means credentials are forwarded in contexts where they should not be, widening the blast radius of a compromised container.
- Fix approach: Track harnessed-9hp.3; requires tightening the detection logic.
-
Location:
src/harnessed/schema.py -
Note: Validation, defaults, coercion, and model definitions are all co-located. Not an immediate risk (it has test coverage via
tests/test_schema.pyandtests/test_schema_thread_safety.py), but splitting validation logic from model definitions would improve readability and isolated testing.
-
Location:
src/harnessed/schema.py:1031 -
Note: The schema emits a user-facing warning that SSE transport is deprecated, but does not fail validation. A recipe silently using
transport: ssewill warn but still assemble. As SSE is deprecated per the architecture constraint ("Streamable-HTTP MCP only"), validation should eventually reject it with a migration hint.
- Location: Filed as harnessed-5jo (P3)
-
Note: The network-bound test stretches suite runtime from ~66 s to ~626 s. It should be marked with a pytest marker (
@pytest.mark.slowor@pytest.mark.network) and excluded from the defaultpytest -qinvocation, with CI running it on a separate job.
-
Location:
src/harnessed/update.py:283,src/harnessed/launcher.py:272,:1070,:2663 -
Note: Four
noqaannotations exist:S310(fixed-host urlopen),BLE001(annotated broad catch),E731/E306(cosmetic style). None suppress real risk; no action needed.
None found in src/harnessed/. All tracked debt lives in beads (43 open issues as of analysis date).
-
No backend abstraction layer: All container operations go through direct
subprocess.run([rt, ...])calls scattered across launcher.py. The backend-abstraction epic (harnessed-0tk) is the right fix, but until it lands there is no seam to swap podman for another runtime in tests, making integration tests depend on a real container runtime. -
No integration tests for project-scoped service lifecycle:
tests/test_launcher_scan.pyandtests/test_launcher_build.pycover image build paths, but the project-scoped service lifecycle (keyed by git-common-dir, bind-mount data dir) has no dedicated test file. The harnessed-wnf and harnessed-1vx bugs live in exactly this untested area. A test that validates mount widening in the host-native path would have caught harnessed-wnf before it was filed. -
Bare worktree / credential gutting incident (harnessed-0cw) has no root-cause prevention: The 2026-07-21 incident (rmtree over live daemon state, credential file zeroed) was mitigated by
_clear_host_home_except_runtime. The root cause of why the credential file was overwritten remains open (harnessed-0cw, P2). Until that is understood, the fix is an incomplete guard.
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)