Skip to content

Epic: Phase 1 — Local Mode Encrypted Store + Password Unlock + TTL + Approvals#82

Merged
NoahCardoza merged 7 commits intomainfrom
feat/issue-48__phase-1-encrypted-store
Feb 25, 2026
Merged

Epic: Phase 1 — Local Mode Encrypted Store + Password Unlock + TTL + Approvals#82
NoahCardoza merged 7 commits intomainfrom
feat/issue-48__phase-1-encrypted-store

Conversation

@helixclaw
Copy link
Copy Markdown
Owner

Fixes #48

Epic: Phase 1 — Local Mode Encrypted Store + Password Unlock + TTL + Approvals

Overview

Implement the foundational encrypted storage layer and local-mode approval workflow as specified in docs/encrypted-storage-spec.md (Sections 2–3, 5).

This phase transforms 2keychains from plaintext secret storage to encryption-at-rest with password-based unlock sessions, TTL-based auto-locking, and notification-based grant approvals in standalone (local) mode.

Goals

  • Encrypted at rest: All secret values encrypted with AES-256-GCM via DEK/KEK architecture
  • Password unlock: User enters password → scrypt KDF → KEK → unwrap DEK → unlock session
  • TTL-based sessions: DEK held in memory with configurable TTL, idle TTL, and max-grants-before-relock
  • Notification approvals: Secrets tagged with approval policies trigger Discord (or other channel) approval requests before grants are issued
  • LocalService implementation: Wire up the existing LocalService stub to real store + workflow + grants

Key Design Decisions

  • Crypto: Node.js built-in node:crypto — AES-256-GCM (AEAD) + scrypt KDF. Zero new dependencies for Phase 1.
  • AAD: "2kc:v1:" + uuid + ":" + ref binds ciphertext to secret identity
  • Store format: ~/.2kc/secrets.enc.json with plaintext metadata + ciphertext values + per-entry nonces + salt
  • Unlock TTL default: 15 minutes (unlock.ttlMs: 900000)
  • Grant persistence: Grants serialized to ~/.2kc/grants.json (survives restarts)
  • Migration: One-time 2kc store migrate command converts plaintext → encrypted
    • Not applicable, no real world user data yet.

Out of Scope

  • Client-server mode (Phase 2)
  • WebAuthn (Phase 3)
  • Signed/JWT grants (Phase 2)
  • Multiple KDF options (Argon2 deferred — scrypt is built-in and sufficient)

Spec Reference

docs/encrypted-storage-spec.md — Sections 2 (Common Foundations), 3 (Variant A: Local Mode), 5 (Notifications)


This PR was created automatically by iloom.

helixclaw and others added 7 commits February 25, 2026 15:42
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add targeted tests for uncovered lines in store.ts, encrypted-store.ts,
unlock.ts, service.ts, grant.ts, config.ts, remote-service.ts, and
secret-store.ts. Replace `npm test` with `npm run test:coverage` in
lefthook pre-commit to enforce the 95% threshold. Add .prettierignore
to exclude .claude/ agent files from formatting checks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@helixclaw helixclaw force-pushed the feat/issue-48__phase-1-encrypted-store branch from fac9274 to 1d49aa6 Compare February 25, 2026 23:42
@helixclaw helixclaw marked this pull request as ready for review February 25, 2026 23:42
@NoahCardoza NoahCardoza merged commit ddec082 into main Feb 25, 2026
1 check passed
@helixclaw
Copy link
Copy Markdown
Owner Author

iloom Session Summary

Key Themes:

  • Claude Code auto-updates mid-session can silently break all shell execution in running agent processes, requiring a retry strategy.
  • The swarm's idempotent phase design (each phase posts a GitHub comment that is detected on retry) is the critical recovery mechanism for failed agents.
  • All 8 Phase 1 child issues are merged; the epic branch is complete and ready for review.

Session Details (click to expand)

Key Insights

  • Auto-update rug-pull: When Claude Code auto-updates, the old versioned binary directory (~/.local/share/claude/versions/X.Y.Z/) is removed. Any already-running agent process loses shell execution capability entirely — posix_spawn '/bin/sh' returns ENOENT. Pure MCP tool calls continue to work, but Bash, Glob, Grep, and any gh-dependent calls all fail silently with exit code 1.
  • Failure phase pattern: All three first-batch agents failed at exactly the same phase (implementation) because that's the first step requiring heavy shell usage (claude -p sub-invocation). Analysis and planning phases use only MCP tools and completed successfully before the failure.
  • Idempotent recovery: Because each swarm workflow phase posts a GitHub comment on the issue, a fresh agent can scan for existing comments and skip already-completed phases. This made retries cheap — agents jumped straight to implementation without redoing analysis/planning.
  • Rebase conflict surface: When multiple sibling branches both modify src/cli/index.ts (to register their new CLI commands), rebasing onto the epic branch produces conflicts in that file. These are mechanical to resolve: keep all imports and command registrations from both sides.
  • Coverage gap locations: The new Phase 1 modules had large uncovered regions concentrated in CLI action handlers (store.ts at 46%) because integration-style tests were sparse. Core modules (encrypted-store.ts, service.ts) had gaps in error paths and locked-state branches.
  • .claude/agents/ Prettier issue: Agent prompt markdown files in .claude/agents/ fail Prettier formatting checks, blocking pre-commit. These files are not project source and should be excluded via .prettierignore.

Decisions Made

Challenges Resolved

  • Stale team member cleanup: After the first failed batch, shutdown requests were sent but some agents (from the initial batch that had already failed) persisted as registered team members, blocking TeamDelete. Sending explicit shutdown messages to each by agent ID resolved this.
  • Duplicate merge agents: Due to the TaskOutput tool not working with team-scoped agents, three merge agents were spawned for the same branch. All three reported success (the second and third found it already merged), causing no harm but indicating that merge operations should not be parallelized.

Lessons Learned

  • TaskOutput does not work for team-scoped agents — checking epic branch git state directly is more reliable than waiting for task output from a merge agent.
  • The il cleanup <issue> command handles worktree removal, branch deletion, and metadata archiving in one step. It correctly identifies branches by issue number pattern (e.g., issue/55-new is found when cleaning up issue 55).
  • --force-with-lease required on push after rebase: because child branches are rebased before merging, the remote branch tip changes, making a regular push reject. --force-with-lease is safe here since we own the branch.
  • src/cli/index.ts is the merge conflict hotspot for any parallel CLI feature branches — all new commands must register there, so sibling branches always conflict on this file.

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.

Epic: Phase 1 — Local Mode Encrypted Store + Password Unlock + TTL + Approvals

2 participants