Read this file first. It is the single source of truth for what Drev is, how it works, and what to build. Subsequent task files (
TASKS/) reference sections here. When in doubt, defer to this document.
Name: Drev
One-line pitch: A CLI that lets engineers resume each other's Claude Code sessions through a shared Git repo.
License: MIT
Language: TypeScript (Node.js ≥20)
Distribution: npm (drev), Claude Code plugin marketplace (v0.1)
Status: Pre-implementation. No code written yet.
Claude Code sessions are single-user artifacts that die when an engineer logs off. When work is handed off (PTO, rotation, ticket reassignment), the receiving engineer rebuilds context from Slack threads, ticket comments, or memory. The first engineer's actual debugging session — the JSONL transcript with every read, edit, and decision — never reaches the next person.
Drev treats Claude Code sessions as first-class shareable artifacts. The producer runs drev share, the session JSONL plus metadata is pushed to a shared Git repo. The consumer runs drev resume <name>, Drev pulls the JSONL, rewrites filesystem paths to match the consumer's environment, and places the file where Claude Code expects it. Native claude --resume <id> then continues the session with full transcript fidelity.
- Not a knowledge base, wiki, or memory product.
- Not a SaaS. No service to host. No signup.
- Not a session-summary tool. Drev moves the actual JSONL, not a summary.
- Not a multi-tool aggregator (yet). v0 is Claude Code only.
┌──────────────┐ share ┌─────────────┐ pull ┌──────────────┐
│ Engineer A │ ─────────► │ Git Repo │ ────────► │ Engineer B │
│ Claude Code │ │ (GitHub etc)│ │ Claude Code │
│ session.jsonl│ │ meta.yaml │ │ rewritten │
│ │ │ session.jsonl│ │ session.jsonl│
└──────────────┘ └─────────────┘ └──────────────┘
│
▼
claude --resume <id>
(native, full fidelity)
The Git repo is the source of truth. Drev never connects engineers' machines directly. Engineer A can be offline by the time Engineer B picks up the session — the repo has it.
These are decisions made during design that should not be re-litigated during implementation. If a task seems to require violating one of these, stop and flag it.
Users supply their own Git remote. Drev never operates infrastructure. Rationale: power-user adoption dies the moment installation requires hosting a service.
Sessions are stored unencrypted in the repo. Trust model is "same as committing source code." Aggressive pre-push redaction handles secret leakage. Encryption is a v0.5+ option, not v0.
No branches for sessions, forks, or visibility. Concurrent shares use per-user directories under users/<username>/ for natural conflict avoidance. Single working branch (main or repo default).
drev list walks the directory tree to build the index dynamically. No shared mutable state file that all writers would conflict on.
No auth. git config user.email is the identity. Anyone with repo write access can act as anyone (same trust model as Git itself).
Cross-platform via Node runtime. Audience already has Node (Claude Code requires it). npm install is one line.
The load-bearing technical piece. Sessions captured on one machine reference absolute paths that don't exist on another machine. Drev rewrites these on resume. Without this, the product does not work.
After preparing the session, drev resume spawns claude --resume <id> as a subprocess. The user runs one command and lands in a resumed Claude Code session. If the spawn fails for any reason (binary not in PATH, OS quirk), Drev prints the manual command as a fallback. The session is always prepared on disk regardless of whether the auto-launch succeeds.
Hooks ship in v0 but install only via drev hooks install. Default is manual share. Reason: auto-modifying global Claude Code config without explicit consent erodes trust.
A Drev-managed Git repo:
team-sessions/
├── README.md # auto-generated by `drev init`
├── .drev/
│ ├── config.yaml # repo-level settings (committed)
│ └── schema-version # plain text, currently "1"
├── users/
│ └── <username>/
│ └── <YYYY-MM-DD>-<name-or-id>/
│ ├── session.jsonl # Claude Code session, redacted
│ └── meta.yaml # session metadata
└── .gitignore
Per-session directories are named <date>-<name> if the user provided a name, else <date>-<short-id>. Examples:
2026-04-30-auth-refactor/2026-04-30-7f3a2b1c/
schema_version: 1
id: 7f3a2b1c-1234-5678-90ab-cdef01234567 # UUID from Claude Code, immutable
name: auth-refactor # user-defined, optional, editable
purpose: share # share | backup
user: fuat # short username
user_email: fuat@example.com # from git config
project: forever-town # derived from project root dir name
project_root: /Users/fuat/work/forever-town # absolute, used for path rewriting
branch: inventory-fix
commit_sha: a1b2c3d4e5f6
created_at: 2026-04-30T14:32:00Z
shared_at: 2026-04-30T18:15:00Z
title: "Debugging inventory desync after merge animations"
summary: |
Multi-line free-form text. Optional.
Auto-generated or user-provided.
visibility: team # team | private
files_touched:
- Assets/Scripts/InventorySystem.cs
- Assets/Scripts/Merge/MergeHandler.cs
parent_session: null # UUID of session this forked from, v0.5+
turns: 47
size_bytes: 312584
redactions:
- { type: anthropic_key, count: 0 }
- { type: openai_key, count: 0 }
- { type: aws_access_key, count: 0 }Required fields: schema_version, id, purpose, user, user_email, project_root, created_at, shared_at, visibility, turns, size_bytes, redactions.
Optional fields: name, project, branch, commit_sha, title, summary, files_touched, parent_session.
schema_version: 1
team_name: forever-town-team
default_visibility: team # team | private
retention_days: 365 # informational, no auto-deletion in v0
redaction_extensions: # team-specific patterns appended to defaults
- "ACME_INTERNAL_[A-Z0-9]+"schema_version: 1
default_repo: ~/.drev/repos/team-sessions # path to local clone
auto_share: manual # manual | auto-private | auto-team
auto_share_idle_threshold_seconds: 60
auto_summarize: false # if true, call API for title/summary
ignore_patterns: # extra redaction patterns
- "MY_PERSONAL_TOKEN_[A-Z]+"
ignore_paths: # paths in JSONL to never share (substring match)
- "secrets/"
- ".env"~/.drev/
├── config.yaml # user config
├── repos/
│ └── <repo-name>/ # local clone of team repo
├── outbox/ # queued shares awaiting network
│ └── <id>/
│ ├── session.jsonl
│ └── meta.yaml
├── logs/
│ └── autoshare.log # rolling auto-share activity
└── .sweep.lock # concurrency lock for autoshare-sweep
src/
├── cli/
│ ├── index.ts # entry, registers all commands
│ ├── commands/
│ │ ├── init.ts
│ │ ├── share.ts
│ │ ├── backup.ts
│ │ ├── list.ts
│ │ ├── resume.ts
│ │ ├── rename.ts
│ │ ├── search.ts
│ │ ├── mark.ts
│ │ ├── sync.ts
│ │ ├── scrub.ts
│ │ ├── hooks.ts # install/uninstall/status
│ │ └── autoshare-sweep.ts # internal command called by hooks
│ └── ui.ts # console output helpers (chalk, ora)
├── core/ # pure logic, no CLI dependencies
│ ├── config.ts # load/save user + repo config
│ ├── identity.ts # current user from git config
│ ├── repo.ts # local repo clone management
│ ├── session.ts # JSONL session reading and stats
│ ├── metadata.ts # meta.yaml schema, validation, I/O
│ ├── claude-paths.ts # encoded-cwd, ~/.claude paths
│ ├── path-rewriter.ts # the load-bearing piece (§7)
│ ├── redaction.ts # secret pattern scanning (§8)
│ ├── git-ops.ts # simple-git wrappers
│ ├── outbox.ts # offline queue
│ └── name-resolver.ts # name-or-id → session resolution
└── lib/
├── errors.ts # typed error classes
└── logger.ts # structured logging to ~/.drev/logs
Critical structural rule: core/ modules have no imports from cli/. The CLI is a thin wrapper over core/. This is the most important architectural constraint in the codebase. Tests live next to logic in core/.
This section is the most important technical content in the document. The product fails if this is wrong.
Claude Code sessions are stored at ~/.claude/projects/<encoded-cwd>/<session-id>.jsonl. The <encoded-cwd> encodes the absolute working directory: every non-alphanumeric character in the path becomes -. So /Users/fuat/work/forever-town becomes -Users-fuat-work-forever-town.
The JSONL file itself contains absolute paths everywhere: tool call inputs, tool call outputs, assistant text, error messages. When Engineer A's session is moved to Engineer B's machine, two things must change:
- The file's location: from A's
<encoded-cwd>to B's<encoded-cwd>. - The paths inside the file: from A's project root to B's project root.
If either is wrong, claude --resume either can't find the file or finds it but can't reconcile the paths with the local filesystem.
function rewritePaths(
jsonl: string,
sourceRoot: string,
destRoot: string
): string;- Input: the original JSONL content as a string.
- Input:
sourceRootis the original engineer's project root (frommeta.yaml.project_root). - Input:
destRootis the resuming engineer's project root (auto-detected viagit rev-parse --show-toplevelor prompted). - Output: a new JSONL string with all occurrences of
sourceRootreplaced bydestRoot, including JSON-escaped occurrences.
function rewritePaths(jsonl: string, sourceRoot: string, destRoot: string): string {
const sourceNorm = normalizePath(sourceRoot); // strip trailing /, posix-style separators
const destNorm = normalizePath(destRoot);
if (sourceNorm === destNorm) return jsonl;
const rawSource = sourceNorm;
const escSource = JSON.stringify(sourceNorm).slice(1, -1); // JSON-escaped form
const rawDest = destNorm;
const escDest = JSON.stringify(destNorm).slice(1, -1);
return jsonl.split('\n').map(line => {
if (!line.trim()) return line;
return line
.split(escSource).join(escDest) // escaped form first (more specific)
.split(rawSource).join(rawDest); // then raw form
}).join('\n');
}Use split/join rather than replaceAll to avoid regex-special-char issues. Order matters: replace JSON-escaped form before raw form, otherwise the raw replacement transforms paths inside escaped strings incorrectly.
- Substring collision:
/Users/fushould not match/Users/fuat. Mitigation: source root must end at a path-separator boundary in the JSONL. Add a boundary-check pass that only replaces when the next character is/,",\, end-of-string, or whitespace. - Regex special characters in paths:
+,(,),[in directory names. Mitigation: split/join is regex-free. - Windows paths: Claude Code uses forward slashes internally even on Windows. Normalize all paths to forward slashes before rewriting.
- Trailing slash inconsistency:
/foo/vs/foo. Mitigation:normalizePathstrips trailing slashes uniformly. - Case sensitivity: macOS may have
/Users/Fuatand/Users/fuatresolving to the same directory. Drev does case-sensitive replacement and documents this. - Source equals destination: no-op early return.
- Source not found in JSONL: valid case, return JSONL unchanged.
- Path appears in assistant text, not just tool calls: caught by the line-level pass.
- Path appears in stderr embedded in tool result: caught by the line-level pass.
- Multi-byte characters in paths: all string operations should handle Unicode correctly (Node default).
Before v0 ships, this must pass:
- Capture a real Claude Code session of ≥30 turns with at least 5 tool calls touching real files.
- Save the JSONL.
- Rewrite paths to a different absolute root (simulating a different user's machine).
- Place at the destination encoded-cwd path.
- Run
claude --resume <id>from the destination working directory. - Ask Claude a specific factual question about the original session.
- Verify Claude answers correctly with details from the original session.
If step 7 fails, the path rewriter has a bug or claude --resume has a context-loading bug (Anthropic issue #15837). Investigate before proceeding.
Defined in src/core/redaction.ts:
const DEFAULT_PATTERNS: RedactionPattern[] = [
{ type: 'anthropic_key', regex: /sk-ant-[A-Za-z0-9_-]{40,}/g },
{ type: 'openai_key', regex: /sk-(?:proj-)?[A-Za-z0-9_-]{40,}/g },
{ type: 'aws_access_key', regex: /AKIA[0-9A-Z]{16}/g },
{ type: 'aws_secret_key', regex: /(?<![A-Za-z0-9])[A-Za-z0-9/+=]{40}(?![A-Za-z0-9])/g },
{ type: 'github_pat', regex: /ghp_[A-Za-z0-9]{36}/g },
{ type: 'github_oauth', regex: /gho_[A-Za-z0-9]{36}/g },
{ type: 'github_app', regex: /(?:ghu|ghs)_[A-Za-z0-9]{36}/g },
{ type: 'slack_token', regex: /xox[baprs]-[A-Za-z0-9-]{10,}/g },
{ type: 'private_key', regex: /-----BEGIN [A-Z ]+PRIVATE KEY-----[\s\S]+?-----END [A-Z ]+PRIVATE KEY-----/g },
{ type: 'jwt', regex: /eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g },
{ type: 'google_api_key', regex: /AIza[0-9A-Za-z_-]{35}/g },
{ type: 'stripe_key', regex: /(?:sk|pk|rk)_(?:test|live)_[A-Za-z0-9]{24,}/g },
];Each pattern has a type (used in the redacted marker and in meta.yaml.redactions) and a regex with the global flag.
Note: aws_secret_key is intentionally aggressive (40-char base64-ish strings) and will produce false positives. This is acceptable: false positives mean an unrelated string gets <REDACTED:aws_secret_key> which is harmless, while false negatives leak a credential.
function redact(jsonl: string, patterns: RedactionPattern[]): {
output: string;
counts: Record<string, number>;
};Apply each pattern in order. Replace matches with <REDACTED:<type>>. Count matches per type. Return the redacted JSONL and counts. Counts go into meta.yaml.redactions.
The patterns used are: DEFAULT_PATTERNS ++ repo.config.redaction_extensions ++ user.config.ignore_patterns. User and repo extensions are user-defined regex strings compiled at runtime.
The first time a user shares to a given repo, Drev shows:
This is your first share to <repo-name>.
Drev will redact common secrets before pushing. Found in this session:
- 0 anthropic_key
- 1 github_pat
- 0 aws_access_key
...
Continue? [Y/n]
Subsequent shares are silent unless redactions occurred, in which case a one-line summary is printed.
drev scrub <id> removes a session from the entire Git history using git filter-repo (shelled out). Force-pushes after rewriting. Requires explicit --confirm flag and shows a warning. Documented as the emergency hatch when redaction missed something.
Every command lives in src/cli/commands/<name>.ts and exports a Commander-compatible action function. Each calls into core/ for actual work.
Initialize Drev with a Git remote.
Behavior:
- Validate the URL is a syntactically valid Git remote (https/ssh/git protocol).
- Determine local clone path:
~/.drev/repos/<local-name>(defaults to last URL segment). - If clone path exists, error with "already initialized."
git clone <url>into the path.- Detect default branch from
git remote show originorHEADref. - If repo lacks
.drev/, scaffold:.drev/schema-version(contents:1).drev/config.yaml(withteam_namefrom URL last segment,default_visibility: team,retention_days: 365)users/.gitkeepREADME.md(templated, explains it's a Drev-managed repo)- Commit and push.
- If repo has
.drev/, validateschema-versionis1. - Update
~/.drev/config.yamlto setdefault_repoto this clone path. - Print success: "Drev initialized. Run
drev shareto share your first session."
Share a session to the team.
Behavior:
- Read user config; load default repo.
- Resolve target session:
- If
--session-idgiven, find it. - Else, find most recent JSONL across all
~/.claude/projects/*/.
- If
- Read JSONL, extract: turn count, files touched (from tool call paths within the project root), creation timestamp.
- Capture git state from the project root:
HEADSHA and current branch (best-effort, omit if not a git repo). - Resolve name:
- If
--namegiven, use it (sanitize: lowercase, replace whitespace with-, remove special chars). - Else, prompt with a suggestion based on the first user prompt (truncated, sanitized). Allow accept/edit/skip.
- If
- Run redaction pass on JSONL.
- Build
meta.yaml:purpose: sharevisibility: privateif--private, else fromrepo.config.default_visibility.- All other fields from §5.1.
git pull --rebasein repo clone.- Compute target dir:
users/<username>/<YYYY-MM-DD>-<name-or-shortid>/. - Write
session.jsonl(redacted) andmeta.yaml. git add,git commit -m "share: <name>",git push.- On push failure: copy session to
~/.drev/outbox/<id>/, log, retry on next sync. - Print summary.
Identical to share but purpose: backup and visibility: private. Name is required (errors if missing).
List available sessions.
Filters:
--mine— only own sessions--team— only team-visible (excludes own private/backups)--backups— only own backups--project <name>— substring match onmeta.project--user <username>— exact match onmeta.user--days <n>— only sessions shared within last N days--limit <n>— cap output (default 20)
Behavior:
git pull --rebasein repo clone (with timeout fallback to local state).- Walk
users/*/*/meta.yaml. Parse each. - Filter according to flags.
- Sort by
shared_atdescending. - Render table: ID-prefix (8 chars), Name, User, Project, "Xh ago", Title.
Prepare a session and launch Claude Code resumed into it.
Behavior:
git pull --rebase.- Resolve argument via
name-resolver:- If looks like UUID prefix (8+ hex chars), match by ID prefix.
- Else, match by
namesubstring. - If multiple matches, list them and exit with error.
- Load
meta.yamlandsession.jsonl. - Determine destination project root:
- If
--into <path>given, use it. - Else, run
git rev-parse --show-toplevelin CWD. - If neither works, prompt the user.
- If
- Compare
meta.commit_shato localHEAD. If different:- Compute diff (which files changed).
- Identify overlap with
meta.files_touched. - Print warning, ask user to continue.
- Run path rewriter:
rewritePaths(jsonl, meta.project_root, destRoot). - Compute Claude Code's encoded-cwd for
destRoot. - Write rewritten JSONL to
~/.claude/projects/<encoded-cwd>/<id>.jsonl. Create directories as needed. - Print: "Resuming '' in ..."
- Locate the
claudebinary:- Check
$PATHviawhich claude(POSIX) orwhere claude(Windows). - If not found, fall through to step 12 (manual mode).
- Check
- Spawn
claude --resume <id>as a subprocess:cwd = destRootstdio = inherit(the user is now talking to Claude Code directly)shell = false(avoid quoting issues)- Drev exits with the subprocess's exit code when it terminates.
- If
--no-launchwas passed, or if step 10 failed to locate the binary, or if the spawn itself errored:- Print fallback instructions:
Session prepared but Claude Code was not launched automatically. Run this command from <destRoot>: claude --resume <id> - Exit 0 (preparation succeeded; only the convenience launch failed).
- Print fallback instructions:
Rationale for the fallback: keeping the manual command available means Drev never blocks the user even if its launch logic breaks (Claude Code not in PATH, unusual shell, Windows path quirks, future Claude Code CLI changes). The user can always copy-paste to continue.
--no-launch flag: lets users opt out of subprocess launching for scripting, CI, or when they want to inspect the prepared file before launching themselves.
Rename a session you own.
Behavior:
- Resolve session.
- Verify ownership:
meta.user_emailmust match currentgit config user.email. Error if not. - Sanitize new name.
git mv users/<self>/<old-dir> users/<self>/<new-date>-<new-name>(preserve date prefix).- Update
meta.yaml.name. - Commit and push.
Search across session metadata.
Behavior:
git pull --rebase.- Walk all
meta.yaml. - Substring match (case-insensitive) against
name,title,summary,files_touched. - Render results as
drev listdoes.
Change visibility or delete.
Flags:
--public/--team— setvisibility: team--private— setvisibility: private--delete—git rm -rthe session directory (note: history retains data; usescrubfor true removal)
Behavior:
- Resolve session.
- Verify ownership for all but
--delete(delete also requires ownership). - Apply change, commit, push.
Pull and drain outbox.
Behavior:
git pull --rebase.- For each item in
~/.drev/outbox/:- Copy to repo, commit, push.
- On success, delete from outbox.
- On failure, leave in place.
- Print summary.
Permanently remove a session from Git history.
Behavior:
- Resolve session. Verify ownership.
- Without
--confirm: print explanation and exit. - With
--confirm:- Verify
git filter-repois available; if not, error with install instructions. - Run
git filter-repo --path <session-dir> --invert-paths. - Force-push.
- Verify
- Print warning that other engineers must re-clone.
Manage Claude Code hooks for auto-share.
Subcommands:
install— add Drev'sSessionEndandSessionStarthooks to~/.claude/settings.json. Preserve all other settings. Tag entries with a marker (e.g.,# managed by drev) for clean uninstall.uninstall— remove only Drev-tagged hook entries.status— show whether hooks are installed and currentauto_sharemode.
Called by hooks. Not intended for direct user invocation but works if invoked.
Behavior: see §10.
Implemented in src/cli/commands/autoshare-sweep.ts. Called by the SessionEnd and SessionStart hooks.
1. Acquire ~/.drev/.sweep.lock. If held, exit silently.
2. Read ~/.drev/config.yaml.
3. If auto_share == "manual", release lock and exit.
4. git pull --rebase in repo clone (with 10s timeout; on timeout, proceed with local state).
5. Build set S of already-shared session IDs by walking users/<self>/*/meta.yaml.
6. Walk all ~/.claude/projects/*/*.jsonl. For each:
a. Skip if mtime within auto_share_idle_threshold_seconds of now.
b. Skip if session ID in S.
c. Determine project root from encoded-cwd. Skip if a .drev-disable file exists at that root.
d. Share with: name = autogenerated, visibility = (private if auto_share=="auto-private" else team), purpose = share.
7. Log results to ~/.drev/logs/autoshare.log (rolling, keep last 30 days).
8. Release lock.
9. Exit silently. Errors go to log only, never to stdout/stderr (hooks are invisible).
If 3+ consecutive sweep runs fail, the next interactive drev command prints a warning: ⚠ Auto-share has failed N times. Run 'drev sync' to investigate.
Package name: @codeturion/drev (unscoped drev was taken; drev-cli rejected by npm's similarity rule against del-cli). Bin name remains drev.
package.json declares one binary:
"bin": {
"drev": "./dist/cli.js"
}Built with tsup, with proper shebang.
Install:
npm install -g @codeturion/drev
Add .claude-plugin/plugin.json and marketplace.json per Claude Code plugin spec. Distribute via:
claude plugin marketplace add codeturion/drev
claude plugin install drev@drev-marketplace
No pkg, nexe, or Bun-compiled binary. Node is a dependency.
Required coverage:
path-rewriter.ts: every edge case in §7.4. Property-based tests with random-shaped paths.redaction.ts: every default pattern with positive and negative examples. User-extension scenarios.metadata.ts: round-trip parse/serialize. Schema validation. Migration stub for future versions.claude-paths.ts: encoded-cwd computation on POSIX and Windows path samples.name-resolver.ts: name vs ID detection, prefix matching, ambiguity handling.
Aim for ≥80% line coverage on core/.
End-to-end on a temp directory acting as both Git remote and two simulated users:
shareproduces correct repo structure.resumeproduces correct file at correct path with correctly rewritten content.- Concurrent shares from two simulated users do not conflict.
- Outbox queues on push failure and drains on
sync. scrubremoves a session from history.
The path rewriter integration with real Claude Code (§7.5) is not unit-testable because it depends on Claude Code's runtime behavior. Document this test in docs/MANUAL_TESTS.md with exact reproduction steps. Run before every release.
Before any production code:
- Capture a real Claude Code session.
- Manually rewrite paths in the JSONL.
- Move to a different
<encoded-cwd>location. - Run
claude --resume <id>from the new directory. - Verify Claude has full context.
If this fails, halt and reassess. The whole architecture depends on it working.
All commands in §9. Auto-share hooks via §9.11 (opt-in). Testing per §13.
Excluded from v0: Claude Code plugin packaging, web UI (never), encryption, forking with lineage, full-text search.
- Claude Code plugin marketplace package (§11.2)
- Polish and bug fixes from v0 user feedback
- Optional API-based title/summary auto-generation
- Session forking with
parent_sessionlineage - Full-text search index
- Optional encryption (age-based)
- Multi-repo support per user
- Read-only viewers (Obsidian plugin, web)
- Cross-tool support: Cursor, Codex, Gemini sessions normalized to a common format
Mitigation: Run §14.1 experiment first. If it fails, fallback options:
- Use Agent SDK's
resumeprogrammatically instead of CLI flag. - Hybrid mode: inject prior session as initial context message (lossier but functional).
- Rescope as session-archive + summary tool.
Mitigation: Ship fast. Position Drev as the open-source reference. If absorbed, that's a good outcome.
Mitigation: Schema version pinning. Detect on read, prompt user to upgrade Drev.
Mitigation: Aggressive default redaction, user-extensible patterns, drev scrub emergency hatch, loud README documentation.
Mitigation: Boundary-aware replacement (§7.4 case 1). Comprehensive unit tests.
- §14.1 experiment passes with a recorded test.
- All §9 commands implemented and unit-tested.
-
core/≥80% line coverage. - One end-to-end integration test passing in CI.
- One real cross-machine resume tested manually and documented.
- All §8.1 default redaction patterns implemented and tested.
- README explains: install, init, first share, first resume in <50 lines.
- Published to npm as
drev. - Demo video showing the holiday-handoff scenario end-to-end.
-
docs/ARCHITECTURE.md(this file),docs/MANUAL_TESTS.md,docs/REDACTION.mdcommitted.
- Strict TypeScript:
tsconfig.jsonwith"strict": true,"noUncheckedIndexedAccess": true. - Error handling: typed errors in
lib/errors.ts, never throw plainErrorfromcore/. - Async I/O: all file/git operations are async. No sync I/O except in CLI bootstrap.
- Logging: structured via
lib/logger.ts. Hooks log silently to file. CLI useschalkfor user-facing output. - No unnecessary dependencies: prefer Node stdlib + the libraries in §2 of DESIGN.md (now §2 of this file via implication). New deps require justification.
- Comments: explain "why," not "what." Path rewriter and redaction modules deserve detailed comments because their correctness is critical.
- Anthropic issue #15837 (Claude Code resume context loading)
- Anthropic issue #38536 (team memory feature request)
- Anthropic issue #40981 (sharing Claude Code conversations with team members)
- Claude Sync (
@tawandotorg/claude-sync) — single-user sync, prior art - CPR (
EliaAlberti/cpr-compress-preserve-resume) — summary-based handoff, prior art - claude-obsidian (
AgriciDaniel/claude-obsidian) — wiki integration, distribution pattern reference
When Claude Code is asked to implement Drev, it should:
- Read this file first. All decisions are recorded here.
- Consult
TASKS/<task>.mdfor the specific scope of the current task. Tasks are intentionally narrow. - Not re-litigate locked decisions in §3. If a task seems to require violating one, stop and ask.
- Implement
core/modules with nocli/imports. - Write tests alongside implementation. Aim for the coverage targets in §13.
- Treat the path rewriter and redaction system as load-bearing. Extra scrutiny, extra tests.
- Defer features explicitly listed as v0.1+ (§14.3-5). No premature implementation.
- Ask before adding dependencies. The dep list is intentionally small.
End of architecture document.