Repository navigation
fix(agents): apply harness review findings - #149
Merged
Merged
Conversation
Move shared Codex, Devin, pi, and Hermes adapter logic into hooks/lib/provider_adapter.py. Make the Devin adapter executable and pass normalized payloads from every provider. Stop mutating Hermes input; log session-start compaction only for compact/resume. Cover NotebookEdit in the file guard and lint, and single-file Grep in the read guard. Refs #148 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Disallow unsandboxed commands in Claude; allow the uv cache and run gh outside the sandbox. Narrow key and token read denials to credential-shaped names so source files stay readable. Require approval for docker build, drop removed Codex features, and declare git as a runtime. Refs #148 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
codex exec no longer accepts --full-auto; the alias only needs a read-only sandbox. Remove opencode, which had no harness hooks or permissions, and check both contracts. Refs #148 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… loads Flag srcset only for non-data candidates and meta refresh or image inputs only when they load. Refs #148 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Let models load project-setup, which other skills name as the setup owner. Create PRs with an explicit body and move adr triggers into its description. Give Issue body, glossary, and completion rules a single owning skill. Drop generic or drifted content; align python, rust, bash, and actions guidance with tools. Replace history-bound skill layout tests with contracts over every skill. Refs #148 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… rule The 2-4 line and one-level nesting quotas contradicted the intent-based extraction rule. They pushed agents toward over-splitting functions. Refs #148 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Sep 23, 2026
Closed
Embedded assets such as TypeScript bridge files tested by Rust no longer demand a JS runner. Unmapped sources of that language still require their own runner and fail closed. Refs #148 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Keep parse-once boundaries, failures as values, exhaustive sum types, and the limit of types. These were lost when the tsdd Type-Driven Design section was removed. Refs #148 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
external_migration is still read by codex 0.155.1, so restore it instead of dropping it. Enable multi_agent_v2 so its wait timeouts take effect; remote_connections stays removed. Refs #148 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude does not expand $HOME in sandbox paths, so the nix and uv cache allowances never applied. Run herdr outside the sandbox like gh, since its socket is denied and escaping is now disabled. Refs #148 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Allow the verification state directory and dprint cache so verify runs without escaping. Ask before herdr commands that drive other panes; send-text, send-keys, and prompt were not covered. Refs #148 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
lefthook 1.13.6 always ran hook commands under a pty, which the Claude and Codex sandboxes deny. Take lefthook from nixpkgs-unstable in home and the devShell, and check the minimum version. Refs #148 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
furedea
added a commit
to furedea/agent-harness
that referenced
this pull request
Sep 28, 2026
…140) Closes #139. Refs furedea/dotfiles#148 (review of furedea/dotfiles#149). ## Summary - **Protected paths are derived, not hand-listed.** `protected_paths_for_runtime` now builds the policy from the same tables the installer uses: `InstalledLayout::synced_directories` (Claude/Codex/Devin/Hermes/pi hooks and the Claude statusline; `render_installation` copies through the same table), `bridges::hermes_plugin_files`, external hook bundle assets, and `InstalledLayout::generated_files` (all managed files plus the generated Claude rule files and the `~/.hermes/config.yaml` sync target). The hand-maintained `static_protected_paths` is removed. `protected_paths.json`, Claude `Edit(...)` deny, `sandbox.filesystem.denyWrite`, and the Codex guarded filesystem all consume this one list. - Newly protected: `~/.devin/hooks/**`, `~/.pi/hooks/**`, `~/.hermes/hooks/**`, `~/.pi/agent/hooks.json`, `~/.pi/agent/extensions/hook_bridge.ts`, `~/.hermes/hooks.json`, `~/.hermes/plugins/agent-harness-hooks/*`, `~/.claude/statusline/**`, `~/.codex/config.toml`, `~/.config/devin/config.json`, `~/.hermes/config.yaml`. - **pi bridge isolation.** `hook_bridge.ts` spawns `python3 -I -B <adapter>`, matching the adapter shebang. - **Source Claude permission rules are kept.** `generate-claude-settings` and `install` dropped every `Bash(...)` entry declared in the source `claude/settings.json`, so a Claude-only rule such as `Bash(dangerouslyDisableSandbox:true)` in `permissions.ask` never reached the generated or synced `~/.claude/settings.json`. Generated settings now keep every source `allow` / `ask` / `deny` entry followed by the generated entries. Each rule is listed once, and a rule in several lists stays only in the most restrictive one (`deny` > `ask` > `allow`), so the merge never widens a permission. `defaultMode` and other permission keys pass through; non-string entries and non-array lists are rejected. ADR-0018 records the decision. ## Notes - Protection stays per-file because the runtime guard compares exact paths. Every file under the source `hooks/` tree, including nested modules such as `hooks/lib/provider_adapter.py`, maps into `~/.claude/hooks/` and is protected; hook runtime logs under `docs/logs/` remain excluded as before. - Skills are rendered but intentionally not protected; they carry no hook or permission settings. - `sync-claude-settings` still replaces the whole `permissions` key, so interactively saved approvals in `~/.claude/settings.json` do not survive a sync; persistent rules belong in the source settings or `command_permissions.json`. ## Tests - `complete_source_protects_every_rendered_provider_file_and_sync_target` walks an installed prefix and asserts every rendered file (except skills) plus each mutable sync target is in `protected_paths.json`, Claude `Edit(...)` deny, and the Codex guarded filesystem. The fixture gains `hooks/lib/provider_adapter.py` and `claude/statusline/statusline.py`. - `pi_bridge_runs_the_adapter_with_an_isolated_interpreter`. - `complete_source_keeps_source_permission_rules_in_generated_claude_settings` and `installed_claude_settings_keep_source_ask_rules_after_sync` cover generate and install-then-sync; `claude_permissions` unit tests cover dedupe and restrictive precedence. - Local: `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, `cargo test`, `nix flake check`, Codex execpolicy bats — all pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…readable Glob-less excludedCommands entries match only the bare command, so gh and herdr stayed sandboxed. The .env* read denial also matched .envrc, which broke nix evaluation in the sandbox. Refs #148 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Re-enable unsandboxed retries for commit, push, and nix, which cannot run in the sandbox. Add an ask rule for dangerouslyDisableSandbox so auto mode never escapes without the user. Bump agent-harness so source permission rules survive generation (furedea/agent-harness#140). Refs #148 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Applies the
agents/harness review findings tracked in #148, apart from the items listed under Departures.Hook adapters
agents/hooks/lib/provider_adapter.py. Each adapter now only declares aProfile.guard_secret_paths.sh.NotebookEdit. The read guard coversGrepwhen its path is a single file.Sandbox and permissions
allowUnsandboxedCommandsstaystrue, because commit signing, push credentials, and the nix daemon cannot be reached from inside the sandbox.Bash(dangerouslyDisableSandbox:true)is an ask rule. With it, auto mode can no longer escape the sandbox on the classifier's approval alone. The rule reaches the installed settings through fix: protect provider files and keep source Claude permission rules agent-harness#140, andflake.lockis bumped for it.$HOME/.cache/nix, which Claude does not expand, so it never applied. It is now~/.cache/nix, and~/.cache/uvis added.excludedCommandsentries use globs (gh *,herdr *,docker *,watchman *). An entry without a glob matches only the bare command, so the old entries never applied.sendrules did not matchsend-textorsend-keys, andagent prompthad no rule, so another agent's approval dialog could be answered without asking.~/.local/state/agent-harness(verification records) and the dprint cache are writable, soverifyruns inside the sandbox.**/*key*,**/*token*, and.env*also matched source files and.envrc. That broke pytest and nix evaluation in the sandbox. They are now limited to credential-shaped names (*.key,*_token,*token*.json,*.pem,.env,.env.*, and so on).docker buildmoves from allow to ask.remote_connectionsfeature.external_migration, because codex 0.155.1 still reads it.multi_agent_v2so its wait timeouts take effect.gitto the manifestruntime_commands.Nix
git cc:codex exec --full-autobecame-s read-only, because the flag was removed.opencodepackage.Skills
project-setupcan now be loaded implicitly.verify_page.pynow detects SVGimage/use,embed,track,input type=image, and meta refresh loads.test_workflow_skill_layout.pywas tied to past changes. It now runs contract tests over every skill: frontmatter, links and anchors, and handoff targets.Verification selection
hook_bridge.tsis embedded withinclude_str!and tested by Rust. Unmapped sources still require their own runner and fail closed.Refs #148
Verification
verification_session.py verify: pytest 1495 passed (full suite), bats 13 passed.nix buildof the home activation package plus thehome-configurationandhost-configurationchecks succeeded.Departures
flake.lockto it.references/. That item was optional.🤖 Generated with Claude Code