Skip to content

Skip an unwritable target instead of aborting the run - #9

Merged
UnbreakableMJ merged 1 commit into
mainfrom
fix-readonly-skip
Aug 23, 2026
Merged

Skip an unwritable target instead of aborting the run#9
UnbreakableMJ merged 1 commit into
mainfrom
fix-readonly-skip

Conversation

@UnbreakableMJ

Copy link
Copy Markdown
Contributor

Two defects, both surfaced immediately by pointing Codex at its real skills directory in #8.

1. is_nix_managed only saw the first hop

It used a single read_link. Codex's skills root here is a chain:

~/.codex/skills → ~/.agents/skills → ~/.local/state/construct/current → /nix/store/…

The first hop is an ordinary path, so engram reported the directory as writable — and emitted no Nix warning — right up until the write failed. It canonicalizes now.

2. The write failure aborted everything

Worse than the missing warning: the EROFS propagated out of install, so a full run stopped at Codex and every harness after it was never reached.

A read-only directory is a fact about the machine, not an engram error — a declaratively-managed skills root is supposed to be immutable. It's now reported per file, counted as skipped, and the run continues.

Verified on the real machine

installed: 0 | skipped: 3
  claude-code  files=3 unwritable=0
  openclaude   files=3 unwritable=0
  codex        files=3 unwritable=3   ← skipped, with the Nix warning attached
  opencode     files=3 unwritable=0
  antigravity  files=4 unwritable=0

Before this change, that same command exited with:

{"error":{"code":"INTERNAL_ERROR","message":"failed to install commands: Read-only file system (os error 30)"}}

The new test makes a skills root 0o555 and asserts both halves: the reason is reported, and Claude Code is still installed afterwards.

Gates

fmt · clippy -D warnings · 256 tests · REUSE 3.3 · makeinfo clean

🤖 Generated with Claude Code

https://claude.ai/code/session_016i16R4GhdSffsboRYq97Fs

Two defects, both surfaced by pointing Codex at its real skills directory.

`is_nix_managed` used a single `read_link`, so it saw only the first hop of a
symlink chain. Codex's skills root here is `~/.codex/skills` ->
`~/.agents/skills` -> `~/.local/state/construct/current` -> `/nix/store/...`;
the first hop is an ordinary path, so engram reported the directory as
writable right up until the write failed. It canonicalizes now.

The write failure was worse than the missing warning: the `EROFS` propagated
out of `install`, so a full run aborted at Codex and every harness after it was
never reached. A read-only directory is a fact about the machine, not an engram
error — a declaratively-managed skills root is *supposed* to be immutable — so
it is now reported per file, counted as skipped, and the run continues.

Verified against the real machine: `install` reports 3 unwritable Codex files
with the Nix warning attached, and still installs Claude Code, OpenClaude,
Opencode, and Antigravity.

Gates: fmt, clippy -D warnings, 256 tests, REUSE 3.3, makeinfo clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016i16R4GhdSffsboRYq97Fs
@UnbreakableMJ
UnbreakableMJ merged commit 295b0f1 into main Aug 23, 2026
5 checks passed
@UnbreakableMJ
UnbreakableMJ deleted the fix-readonly-skip branch August 23, 2026 23:57

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f61e1e1deb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/install.rs
Comment on lines +388 to +390
match managed_file::write_managed(&path, &body, WritePolicy::Owned, dry_run) {
Ok(w) => w,
Err(e) if is_unwritable(&e) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Route plugin manifests through the unwritable skip path

When Antigravity's plugin directory is read-only, this handler skips the three SKILL.md writes, but the subsequent plugin.json write still uses a bare ? and propagates the same PermissionDenied/ReadOnlyFilesystem error. Consequently, this plugin-backed target still makes install fail instead of returning the per-file results promised by this change; apply the same recovery path to the manifest write.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant