feat: agent instructions editor in Settings #22
No reviewers
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Depends on
#21 feat: operator-approved port previews (#3)
lz/agent-nexus
Reference
lz/agent-nexus!22
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/agent-instructions"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
A discoverable Settings tab for editing the shared
~/.claude/CLAUDE.mdfile that every claude session sees as system context. Nexus ships a sensible default documenting the affordances agents need to know about (notify-preview, the worktree/branch model, what they can't do), seeds it on first boot, and respects operator deletions thereafter.nexus/src/lib/server/agent-instructions/withread/write/resetToDefaultagainst a single hardcoded path underSHARED_CONFIG_DIR.seedOnBootis one-shot, gated by aninstance_settingsflag — deleting the file post-seed stays deleted; "Reset to default" in the UI is the explicit way back.GET/PUT+POST /reset), all auth-gated by the existing hooks./settingswith a monospace textarea, Save, Reset to default, byte counter,beforeunloadguard against accidental loss.Spec: docs/superpowers/specs/2026-05-25-agent-instructions-editor.md
Plan: docs/superpowers/plans/2026-05-25-agent-instructions-editor.md
Depends on
PR #21 (operator-approved port previews). The bundled default CLAUDE.md documents the
notify-previewhelper that PR introduces. Land port previews first, then rebase or mergemaininto this branch before merge.Implementation notes
nexus/static/default-CLAUDE.mdand pinned to LF via.gitattributes(so Windows contributors can't accidentally check in CRLF that would break theisDefaultbyte-equality check on every fresh install).seed.tswrites bothagent_instructions_seeded='true'andagent_instructions_last_seeded_hash=<sha256>toinstance_settings. The hash is unused by v1 logic but enables future drift detection (v2) without needing a migration.service.ts:resetToDefaultdeliberately bypasses themax_file_bytessize check because the bundled default is trusted, code-shipped content.Review status
Per-task TDD + code-quality reviews ran during implementation. The pure helpers (paths, default, hash), service, seed, route handlers all got both spec and quality review with follow-up fix commits where reviewers flagged issues (path arithmetic in the prod-adapter-node resolver, ENOENT discrimination in seed's existence check, error-type pinning in tests, etc.). A final cross-cutting review confirmed end-to-end coherence. The Settings UI panel and AGENTS.md fact skipped per-task quality review to keep cadence.
Test plan
pnpm --dir nexus testonnode:22-alpine. Locally on Windows, seed tests skip via thesqliteAvailablepattern; CI exercises them fully.pnpm --dir nexus exec tsc --noEmitpasses locally; CI re-runs.~/.claude/CLAUDE.mdmatches.isDefault: false; Reset recreates the file.SELECT * FROM instance_settings WHERE key LIKE 'agent_instructions%'shows two rows after first boot.git check-attr eol nexus/static/default-CLAUDE.mdreportslf.- read: returns {content, isDefault}; missing file is empty + isDefault=false - write: atomic .tmp + rename; rejects content over max_file_bytes - resetToDefault: writes DEFAULT_CONTENT, returns it - 10 tests with mocked paths/singletons/default + real FS in a tmpdir - Runs on Windows (no sqlite dependency)Per code review: - service.ts: drop redundant Number() wrap; destructure getInstanceSetting's value field to match every other callsite in the codebase. - service.test.ts: tighten the 'rethrows non-ENOENT' assertion from a bare .rejects.toThrow() to .rejects.toMatchObject({ code: 'EISDIR' }) so the test can't silently pass on a future mock-induced ENOENT regression.- GET /api/settings/agent-instructions → {content, isDefault, maxBytes} - PUT /api/settings/agent-instructions {content} → 204 / 400 on oversize / 500 on IO - POST /api/settings/agent-instructions/reset → {content, isDefault: true} - Auth-gated by hooks.server.ts (no carve-out needed; operator-only by default)When developing through the proxy from PR #21, agents currently have to be told about it after something breaks, e.g. a Next.js dev server starts fine, but the browser-side HMR socket hits ws://NEXUS_SERVER:8080/... and Next.js refuses it as a cross-origin dev request. The fix (allowedDevOrigins: ['devops.lan'] in next.config.js) is trivial once you know the hostname; the cost is the round-trip of discovery.
The proxy hostname should be injected into CLAUDE.md so agents see it from turn one. That means dev-server setups (Next.js allowedDevOrigins, Vite server.hmr.host, CRA WDS_SOCKET_HOST, etc.) can be configured up front.