docs-readme-host-limitation-unshare-eperm
Root cause. The installed tree at /usr/local/lib/terminal-jail (read-only install) had no docs at all, and the canonical project root the installed wrapper points to (~/terminal-jail/) was missing entirely. The gaps were rebuilt from code reality plus runtime verification:
TJ-GAP-015 (unshare EPERM): Created README.md with the fix pattern requested — the headline example is annotated inline with a one-line host-limitation caveat (unshare: unshare failed: Operation not permitted on hosts denying unprivileged PID namespaces), and the verified working fallback (./standalone/terminal-jail --user echo ..., userns, nobody=65534, rc=0 on the TJ-GAP-015 host) is shown directly beneath it. The FAQ/Host-Limitations section remains but is no longer the only carrier of the caveat. docs/HOST-LIMITATIONS.md holds the full evidence matrix and detection commands.
TJ-GAP-016 (AGENTS.md vs. code reality): Created AGENTS.md that describes the Hermes plugin as observability-only — pre_tool_call can only block/allow (never transform), transform_terminal_output returns None, and transform_command/transform_exec_command are importable but not wired into Hermes core (HOOK-GAP-01, dead code at runtime). The real sandbox is explicitly the standalone CLI + seccomp loader. The doc includes the false-claim warning and the rule to keep examples' caveats inline.
Files: README.md, AGENTS.md, docs/HOST-LIMITATIONS.md, tests/verify_docs.py (13 checks), plus restored source copies at the canonical root.
Verified on this host (container, unprivileged kara, no sudo): - `unshare --pid --fork --mount-proc --kill-child=SIGKILL true` → **rc=1, `Operation not permitted`** — reproduces the exact headline failure the gap report describes. - `unshare --user true` → **rc=0**, runs as `uid=65534(nobody)` — confirms the "userns, nobody=65534" layer works. - `unshare --user --pid --fork true` → rc=1 here, because this container also denies the userns `uid_map` write (`--map-root-user` → `write failed /proc/self/uid_map: Operation not permitted`). Documented as **Tier 2** (nothing works unprivileged) vs. the gap-report host's **Tier 1** where the `--user` fallback returned rc=0. - Installed CLI and repo copy behave identically: `./standalone/terminal-jail echo hi` → `unshare: unshare failed: Operation not permitted` rc=1; interruptor bridge absent → fail-open warning (documented). - `bash -n` on the CLI and `py_compile` on all 4 modules pass. - Test suite: 13/13 (D1–D6 doc-consistency incl. inline-caveat placement *before* the FAQ heading, explicit denial of plugin sandbox claims; R1–R4 runtime/syntax). `python3 tests/verify_docs.py` exits 0.
{"model": "deepseek-v4-flash", "problem_class": "docs-readme-host-limitation-unshare-eperm", "result": "passed", "tests": 13}Root cause. The installed tree at /usr/local/lib/terminal-jail (read-only install) had no docs at all, and the canonical project root the installed wrapper points to (~/terminal-jail/) was missing entirely. The gaps were rebuilt from code reality plus runtime verification:
TJ-GAP-015 (unshare EPERM): Created README.md with the fix pattern requested — the headline example is annotated inline with a one-line host-limitation caveat (unshare: unshare failed: Operation not permitted on hosts denying unprivileged PID namespaces), and the verified working fallback (./standalone/terminal-jail --user echo ..., userns, nobody=65534, rc=0 on the TJ-GAP-015 host) is shown directly beneath it. The FAQ/Host-Limitations section remains but is no longer the only carrier of the caveat. docs/HOST-LIMITATIONS.md holds the full evidence matrix and detection commands.
TJ-GAP-016 (AGENTS.md vs. code reality): Created AGENTS.md that describes the Hermes plugin as observability-only — pre_tool_call can only block/allow (never transform), transform_terminal_output returns None, and transform_command/transform_exec_command are importable but not wired into Hermes core (HOOK-GAP-01, dead code at runtime). The real sandbox is explicitly the standalone CLI + seccomp loader. The doc includes the false-claim warning and the rule to keep examples' caveats inline.
Files: README.md, AGENTS.md, docs/HOST-LIMITATIONS.md, tests/verify_docs.py (13 checks), plus restored source copies at the canonical root.
Verified on this host (container, unprivileged kara, no sudo): - `unshare --pid --fork --mount-proc --kill-child=SIGKILL true` → **rc=1, `Operation not permitted`** — reproduces the exact headline failure the gap report describes. - `unshare --user true` → **rc=0**, runs as `uid=65534(nobody)` — confirms the "userns, nobody=65534" layer works. - `unshare --user --pid --fork true` → rc=1 here, because this container also denies the userns `uid_map` write (`--map-root-user` → `write failed /proc/self/uid_map: Operation not permitted`). Documented as **Tier 2** (nothing works unprivileged) vs. the gap-report host's **Tier 1** where the `--user` fallback returned rc=0. - Installed CLI and repo copy behave identically: `./standalone/terminal-jail echo hi` → `unshare: unshare failed: Operation not permitted` rc=1; interruptor bridge absent → fail-open warning (documented). - `bash -n` on the CLI and `py_compile` on all 4 modules pass. - Test suite: 13/13 (D1–D6 doc-consistency incl. inline-caveat placement *before* the FAQ heading, explicit denial of plugin sandbox claims; R1–R4 runtime/syntax). `python3 tests/verify_docs.py` exits 0.
{"model": "deepseek-v4-flash", "problem_class": "docs-readme-host-limitation-unshare-eperm", "result": "passed", "tests": 13}