Skip to content

WIP: feat: detached artifacts mode + per-file agent visibility gating#106

Merged
gbrbks merged 14 commits into
mainfrom
feature/detached-artifacts
Jul 1, 2026
Merged

WIP: feat: detached artifacts mode + per-file agent visibility gating#106
gbrbks merged 14 commits into
mainfrom
feature/detached-artifacts

Conversation

@gbrbks

@gbrbks gbrbks commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

What this adds

An opt-in detached storage mode that decouples Archie's generated artifacts from the working tree. Artifacts live in an external store (~/.archie/projects/<id>/) and surface into the repo via symlinks, so the tree stays clean — the only committed Archie file is .archie-link.json. The default (repo) mode is unchanged.

On top of the decoupling, the viewer gains an Exposure tab: a per-file visibility switch over the generated markdown the agent reads — per-folder CLAUDE.md (intent-layer) and .claude/rules/*.md (blueprint). Toggle a file off and it's removed from the agent's view; the content stays safe in the store. This is visibility only — it does not touch rules.json enforcement. The tab is detached-mode only.

Try it

npx @bitraptors/archie /path/to/project --detached
# then in the agent: /archie-deep-scan
# then: /archie-viewer   → open the "Exposure" tab
git status   # clean — only .archie-link.json tracked

Opt back out anytime (reversible, nothing lost):

python3 .archie/linker.py detach .

How it works

  • Three new zero-dep modules: link_store.py (store location + manifests), link_strategy.py (symlink / NTFS-junction / copy fallback + safety invariant), linker.py (orchestration + CLI: bind | reconcile | externalize | status | attach | detach).
  • .archie/ is a single always-on directory symlink (write-through; holds tooling/hooks/raw JSON the agent never reads). Existing scanner/renderer/intent-layer write through it unchanged.
  • Generated markdown is externalized per file and gated individually; the renderer + intent-layer call externalize after writing.
  • Cross-platform: POSIX symlinks; Windows junctions for dirs, copy fallback for files (never hard-fails).

Where things live

Committed Gitignored symlink → store Store (source of truth)
.archie-link.json
root CLAUDE.md/AGENTS.md ✅ (lean)
.claude/rules/*.md ✅ per-file (gateable)
per-folder CLAUDE.md ✅ per-file (gateable)
.archie/ (blueprint, findings, tooling) ✅ whole dir (always on)

Quality

  • 42 detached-specific tests (tests/test_link_store.py, test_link_strategy.py, test_linker.py, test_intent_layer_detached.py, test_viewer_exposure.py, test_detached_e2e.py), plus an adversarial-review pass that found and fixed real state-integrity bugs:
    • re-running bind no longer wipes the per-file registry (every npx --detached reinstall hit this);
    • stale docs no longer resurrect on reconcile/detach (renderer prunes what it no longer produces);
    • copy-fallback only deletes a file that still byte-matches the store source (never a user edit);
    • git-tracked files are never silently swapped to symlinks;
    • tolerant of old-shape state; dropped an inert @import line.
  • scripts/verify_sync.py passes (canonical ↔ npm assets ↔ viewer mirrors aligned); viewer builds clean.

Known POC limits (seams left in)

No server backend / team sync (detached-local is per-developer; the future remote store is the seam), no snapshot/versioning, no per-project mode layering. attach (converting an existing project) won't relocate already-committed artifacts.

Design: docs/archie-detached-artifacts-design.md.

🤖 Generated with Claude Code

gbrbks and others added 12 commits June 30, 2026 08:36
Brainstormed design for opt-in detached-artifacts mode: external folder as
source of truth, symlink/junction/copy presentation into a clean working tree,
viewer as exposure control plane. In-repo mode stays the default.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ach + CLI

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
cmd_merge relocates freshly-written per-folder files to the external store in
detached mode; no-op in repo mode. Test loads standalone modules directly so it
runs on Python 3.9 (the engine package needs tomllib/3.11+).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds an Exposure tab to the local viewer that toggles category + per-file
artifact visibility via /api/exposure; inert in repo mode.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- archie.mjs parses --detached and runs linker bind post-install
- bind absorbs pre-existing .archie/ contents (npm-copied tooling) into the
  store before symlinking, so the scripts survive the dir->symlink swap
- mirror link_store/link_strategy/linker + updated intent_layer/viewer + viewer
  source into both asset trees (verify_sync passes)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
.archie/ is infrastructure (tooling/hooks/raw JSON the agent never reads) and is
always exposed; only rules + folder_context are gateable. Adds end-to-end
lifecycle test and documents storage modes in CLAUDE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…lueprint)

Course-correct the gatekeeping to match intent: a per-FILE visibility control
over the generated markdown the agent reads, in two groups — intent_layer
(per-folder CLAUDE.md) and blueprint (.claude/rules/*.md). Detached mode only.

- .claude/rules/*.md are now externalized per file (not one dir symlink), so
  each blueprint doc toggles individually; renderer externalizes after render.
- .archie stays a single always-on infrastructure symlink (never gated).
- placements carry target + category; exposure categories are intent_layer +
  blueprint (dropped the misleading 'rules' naming — unrelated to rules.json
  enforcement curation).
- viewer Exposure tab reframed as a per-file browser; hidden entirely in repo
  mode (LocalPage gates on /api/exposure mode).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…back

Adversarial-review fixes:
- bind now MERGES placements (refreshes only the infra entry) instead of
  overwriting — re-running bind (every npx --detached install) no longer wipes
  the per-file registry and orphans links. [HIGH]
- renderer prunes blueprint docs it no longer produces (store + placement +
  link) via prune_blueprint(keep_set), distinguishing stale (renderer dropped)
  from hidden (user toggled) so stale docs can't resurrect on reconcile/detach.
- reconcile/detach tolerate old-shape placements missing 'target' (_target_of).
- drop the inert @import pointer; bind no longer touches CLAUDE.md (detach still
  strips the legacy marker for old repos).
- renderer externalize/prune logs failures to stderr instead of silent pass.

Regression tests cover re-bind preservation, stale-vs-hidden prune, and the
old-shape fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ked files

Address remaining adversarial-review notes:
- remove_managed(copy) now only deletes a file that still byte-matches the store
  source; a user edit or foreign file at that path is preserved. Upholds 'never
  delete a file we didn't place' for the Windows copy fallback (no link to
  verify). target threaded through reconcile/detach/prune callers.
- externalize_file skips git-tracked files (git ls-files): a user-committed
  per-folder CLAUDE.md stays a real tracked file — no surprise file->symlink
  swap, no silently relocated content. Untracked generated files still
  externalize.

Tests: copy unmodified/edited/no-target safety; tracked-skip + untracked-still-
externalizes (real git repo).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
archie Ready Ready Preview, Comment Jun 30, 2026 11:19am
archie-viewer Ready Ready Preview, Comment Jun 30, 2026 11:19am

…erimental)

Interactive install now asks 'Enable detached mode?' (default No) with a clear
explanation of what it does (external store + symlinks, clean tree, per-file
Exposure tab), that it's experimental, that it's reversible (linker detach), and
how to enable later (--detached or linker attach). Non-TTY/CI installs default
to off; the --detached flag still skips the prompt and forces it on.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
link_store assumed Path args; a str caller would crash on '/'. Real callers
(linker coerces, viewer passes Path) never hit it, but coercing removes the
footgun. No behavior change for existing callers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@gbrbks gbrbks changed the title feat: detached artifacts mode + per-file agent visibility gating WIP: feat: detached artifacts mode + per-file agent visibility gating Jun 30, 2026
@gbrbks gbrbks merged commit 4cf6d1e into main Jul 1, 2026
4 checks passed
@gbrbks gbrbks deleted the feature/detached-artifacts branch July 1, 2026 08:55
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