Changelog¶
All notable changes to SiftCoder. Format follows Keep a Changelog, versioning is SemVer.
[1.2.7] — 2026-05-10¶
Fixed¶
- Daemon never auto-drained without MCP host sampling — v1.2 added an MCP-side eager-drain loop, but sessions where Claude Code didn't advertise
sampling(or where the MCP server hadn't initialized) left the daemon idle even with a fully configured backend. Capture worked (UDS path is independent), drain didn't fire. Found via real workspace:/Users/sam/Documents/ADHDhad 28 raw events accumulating over 50 minutes withGEMINI_API_KEYset anddrain backend selected: gemini-2.0-flashlogged at boot, butsummarized=0throughout because nothing kicked drain. - Added
src/memory/daemon/periodic-drain.ts— adaptive-backoff drain loop mirroring the MCP-side pattern, runs daemon-side whenever asummarizeris configured. 2× empty-tick backoff capped atmaxBackoffSteps, snaps to base on a productive drain. Single concurrency guard. Errors logged but never thrown. - Tunable:
SIFTCODER_DAEMON_DRAIN_MS(default 60s; 0 disables),SIFTCODER_DAEMON_DRAIN_BATCH(default 8). - Tests: 6 new cases covering disabled paths, backoff behaviour, productive-drain reset, error survival.
Coverage¶
The two drain paths are now symmetrical — MCP-side handles host-sampling sessions, daemon-side handles backend-API-key sessions. Both run with the same backoff shape.
[1.2.6] — 2026-05-10¶
Added¶
siftcoder savingsCLI verb +savingsRPC kind. The savings report (capture / drain / spend / compression / net token savings) was previously only reachable via/api/savingsHTTP or the SPA Overview tab. Adds parity with the rest of the operator surface —mem statsshows throughput,mem savingsshows tokens./siftcoder:mem savings [--json]slash command.
[1.2.5] — 2026-05-10¶
Audit pass on the v1.2 line. Three measured findings, three fixes.
Fixed¶
- Streaming search ran every subquery twice —
streamingHybridSearchemitted BM25 + vector stages from one set of queries, then calledhybridSearchfor the final stage which re-ran BM25 + embedding + vector. Verified by instrumented count:{ searchFts: 2, embed: 2 }per stream_search request. Refactored: extractedrunRetrievalStages(BM25 + vector preflight) andfuseAndRank(RRF + decay + supersede + rerank) so bothhybridSearchandstreamingHybridSearchshare the work. Now{ searchFts: 1, embed: 1 }per request, matching non-streaming. Comment claiming "guarantees parity" was rationalization for the duplication. - Doctor reranker probe leaked money on idle workspaces —
mem watchpolled doctor every 20s; doctor pinged the reranker server every call → 4320 paid Cohere/TEI/Jina API calls per idle day. Added 60s probe cache at the daemon level.req.heal=truebypasses the cache so an explicitmem doctor --healalways gets ground truth. Cached responses include acached: trueflag in the reply.
Verified (no fix needed)¶
- Auto-edge capture latency — measured: 52µs/event baseline → 160µs with auto-edges (Edit) → 538µs worst case (Bash with 8 path tokens). Capture budget is 250ms; auto-edges uses ≤0.2% of it. Phantom concern.
Internals¶
runRetrievalStagesandfuseAndRankare private helpers inretrieval.ts. Public surface (hybridSearch,streamingHybridSearch) unchanged.resetRerankerProbeCacheexported fromserver.tsfor tests; module-level cache is aletso tests can isolate.
[1.2.4] — 2026-05-10¶
Loose-end polish.
Added¶
processFrameextracted fromstartServersocket loop — streaming branch now unit-testable in isolation. 3 new test cases (single-frame ping, full stream_search emit pattern, error-frame on stage failure). Closes thec8 ignorecoverage gap on the streaming dispatch path.- CLI
mem stream-searchANSI colors + per-stage timing —[bm25]blue,[vector]cyan,[final]green,[done]dim, plus elapsed-ms badge per stage and total.NO_COLORenv var and--no-colorflag honored. Plain output preserved when stdout is not a TTY (pipes / scripts). mem watchupgraded — adds backlog ETA, cache hit rate, pinned count, integrity status, reranker reachability badge. Doctor poll every 10 ticks (default 20s) layered on the per-tick stats RPC. Color-coded integrity / reranker state.
[1.2.3] — 2026-05-10¶
Tail of the v1.2 cleanup wave.
Added¶
- SPA Federation tab +
/api/federate-searchroute —mem_federate_searchhad been daemon/CLI-only since 1.1.0. External callers no longer need the legacyPOST /RPC frame. Tab provides query / k / prefix / max-workspaces controls; results tagged by workspace key.
Docs¶
- ARCHITECTURE.md refresh — captures every shipped feature since the v1.1 doc-pass: knowledge-graph queries, auto-edge inference, MCP eager-drain, streaming hybrid search, cross-encoder reranker, 11 SPA tabs. Adds four new design decisions (D8–D11).
[1.2.2] — 2026-05-10¶
Operational hardening. Three issues that all surfaced during the v1.2.1 plugin-cache install:
Fixed¶
- Missing native binding crashes daemon with cryptic
database is locked—npm install --silent(used by some plugin-marketplace install paths) skips better-sqlite3's postinstall on certain npm versions. The bindings.js fallback then triggers a wasm path that interprets WAL state as a lock.bin/siftcoder.mjsnow checks fornode_modules/better-sqlite3/build/Release/better_sqlite3.nodeonstartandopenStorage, runsnpm rebuild better-sqlite3automatically when missing. - Daemon main-loop catch swallows stack —
main().catch(err => stderr.write(err.message))was hiding the line number. Now writeserr.stack ?? err.message. Future first-boot failures will be diagnosable on first sight.
Added¶
- Reranker reachability probe in
mem doctor— whenSIFTCODER_RERANKER_URLis set, doctor callsreranker.ping()(single 1-doc score round-trip) and reports{ configured, ok, latencyMs, error? }. Surfaced in the SPA Health tab as areachable | unreachable | disabledtag with latency. A silently-broken reranker no longer degrades search quality unnoticed. AsyncReranker.ping?(): Promise<{ ok, latencyMs, error? }>— optional health probe.crossEncoderToRerankerimplements it via a 1-doc score call.
[1.2.1] — 2026-05-10¶
Build fix. The TypeScript compiler doesn't copy non-.ts assets, so dist/memory/web/static/ was never populated. The HTTP bridge resolves index.html / app.js / style.css from that path at runtime, so any installation built from a fresh checkout returned 404 on /?token=… even though the source files sat untouched in src/memory/web/static/. Latent since the SPA shipped; only surfaced when the daemon was restarted on a freshly built dist.
Fixed¶
- SPA shell 404 from compiled dist —
npm run buildnow runsscripts/copy-static.mjsaftertscto copysrc/memory/web/static/*→dist/memory/web/static/*. The script logs the file count so build output makes the copy visible.
[1.2.0] — 2026-05-10¶
Knowledge-graph + retrieval-quality release. Nine PRs (#27–#35) closing every deferred roadmap item from the 1.1.0 audit. Test count 800 → 857; +57 tests across new modules. Capture path now seeds the provenance graph automatically; search gains both progressive streaming and opt-in cross-encoder reranking.
Added — knowledge graph¶
- Auto-edge inference at capture (PR #32) —
src/memory/auto-edges.tswrites structural provenance edges as events land:event → file (edits)for Edit/Write/Read/MultiEdit,event → file (references)for Bash path-tokens, and aderives_fromchain to the prior event in the same session. All inferred edges taggedsource='auto'. Disable withSIFTCODER_AUTO_EDGES=0. Meansmem_graph_subgraph/hubs/pathnow produce non-empty results on a fresh workspace. mem_graph_subgraph+mem_graph_hubs(PR #29) — bidirectional BFS subgraph extraction (with edgeType filter + maxEdges cap) and top-degree node ranking with optional kind filter. Tools, HTTP routes (/api/graph/subgraph,/api/graph/hubs), CLI verbs (graph-subgraph,graph-hubs).mem_graph_path(PR #31) — shortest path between two nodes via undirected BFS over the provenance graph; preserves edge direction in the response. CLI verbgraph-path. Side-fix:case 'why'returned an unawaited Promise; now returns the resolved edges.
Added — retrieval quality¶
- Cross-encoder reranker (PR #34) — opt-in HTTP scoring via
SIFTCODER_RERANKER_URL.HttpCrossEncoderauto-detects Jina/TEI ({scores}) and Cohere ({results}) response shapes. Adapter fails open: any scoring error falls back to baseline RRF order so a flaky reranker never breaks search. Wired into/api/search,mem_search,mem_context_budget. Zero binary deps in default install. - Streaming hybrid search (PR #35) — new
stream_searchRPC kind emits BM25 → vector → final stages as separate frames on one socket connection.MemoryClient.sendStreamis an AsyncGenerator with per-frame progress timeout. CLI verbsiftcoder stream-searchrenders each stage progressively.streamingHybridSearchreuses non-streaminghybridSearchfor the final stage to guarantee parity. - MCP eager-drain loop (PR #28) —
src/memory/mcp/drain-loop.tspolls daemon backlog and drains via host sampling without waiting formem_search. Adaptive backoff (2× per empty tick, capped) keeps idle workspaces quiet; resets to base cadence on a productive drain. Configurable:SIFTCODER_MCP_DRAIN_MS(default 60s; 0 disables),SIFTCODER_MCP_DRAIN_BATCH(default 4).
Added — web UI¶
- Health, Pinned, Sessions, Symbol tabs (PR #27) — surfaces
/api/stats,/api/doctor,/api/pinned,/api/symbol-search,/api/replayin the SPA. AddsGET /api/sessionsfor browser-friendly session listing (was RPC-only). - Graph tab (PR #30) — subgraph explorer with click-pivot edge cells + hub sidebar with kind filter. Turns the SPA into a graph walker.
- Path-finding form (PR #31) — second form on the Graph tab for
/api/graph/path. - Patterns tab + HTTP parity (PR #33) —
/api/patterns,/api/session-digest,/api/as-ofso external callers no longer need the legacyPOST /RPC frame. Patterns tab surfaces recurringinput_hashbuckets across sessions.
Fixed¶
case 'why'returned{}not edges (PR #29) — thetracePromise was being JSON-serialized without await. The endpoint now returns the resolved edge list.- Empty graph on fresh workspace (PR #32) — graph features advertised but produced empty results until human edges or CDG ingest landed; auto-edge inference closes this.
Internals¶
- 9 PRs, all squash-merged.
- New modules:
auto-edges.ts,cross-encoder.ts,mcp/drain-loop.ts,stream-search.integration.test.ts. - New protocol kinds:
graph_subgraph,graph_hubs,graph_path,stream_search. - New storage methods:
previousEventInSession,topProvenanceDegree. - New ProvenanceStore methods:
subgraph,topHubs,shortestPath. - WebDeps + ServerDeps gained an optional
reranker: AsyncReranker | null.
[1.1.0] — 2026-05-09¶
Major mem-subsystem expansion. 13 PRs (#8–#20) over a single audit-driven session, taking the memory system from a fragile capture-and-summarize pipeline to a self-maintaining knowledge graph with operator tooling and host-driven summarization. Test count 530 → 778, coverage 89.5 % → 92.6 %.
Added — capture & retrieval¶
- MCP host sampling drain (PR #9) — when the host advertises
sampling, the plugin delegates summarization to the host LLM viasampling/createMessage. No API key required inside Claude Code; GLM/Gemini/Ollama/Anthropic remain as direct-API fallbacks. - vec0 indexed retrieval (PR #10) —
sqlite-vecauto-loaded as an optional dep;Storage.searchVecreplaces JS-side cosine when enabled. Backfill restores the vec table from existing embeddings on first boot. - Per-tool decay (PR #10) — Edit/Write 30 d, Read 14 d, Bash 3 d, etc. Hits carry their originating tool through retrieval.
- Corpus-wide IDF reranker (PR #10) — IDF computed over recent 2 k summaries, cached with 5 % drift invalidation.
- Async symbol annotation (PR #13) —
events.symbols_jsonpopulated by a backgroundSymbolWorker; capture hot path no longer runs CDG / regex inline. - Cross-session continuity (
mem_thread) (PR #13) — surface other sessions sharing aninput_hash. - Federation surface (
mem_federate_search) (PR #14) — cross-workspace consented search. - Symbol search (
mem_symbol_search) (PR #14) — match bykind:nameexact or substring on the name. - Stats (
mem_stats) (PR #14) — throughput, backlog ETA, cache hit rate, top tools. - Replay (
mem_replay) (PR #15) — session chronology with summaries joined. mem_captureMCP tool (PR #15) — agents push facts directly with optional TTL.- Eight web UI HTTP endpoints (PR #15) — stats, doctor, pinned, symbol-search, thread, replay, pin, unpin.
- Live watch TUI (PR #16) —
siftcoder watchpolling dashboard. - Eager drain (PR #16) —
mem_searchramps drain batch with backlog (8/16/32 above 50/200/500 pending). mem_context_budget(PR #16) — greedy fill: ranked summaries fitting under a token cap.mem_compact(PR #17) — VACUUM + cache prune + dim-mismatched embedding cleanup + FTS rebuild.mem_patterns(PR #17) — recurringinput_hashbuckets across sessions.mem_session_digest(PR #18) — concat session summaries into one chronological text.mem_auto_pin_patterns(PR #18) — one-shot curation: pin everything in a recurring pattern.siftcoder hooks <install|show>(PR #18) — bootstrap PostToolUse capture into.claude/settings.local.json.siftcoder captureCLI (PR #19) — closes the gap left byhooks install.siftcoder maintenance(PR #19) — one-shot nightly: sweep + compact (+ optional auto-pin).mem_as_of(PR #19) — point-in-time view: counts + summaries as they existed at a timestamp.mem_dashboard(PR #20) — single round-trip combined view (stats + doctor + pinned + patterns).
Added — pinned summaries & schema¶
pinned_atcolumn (PR #11) — user-curated long-term memory exempt from supersede + decay.expires_atcolumn (PR #12) — per-event TTL with automatic sweep.symbols_jsoncolumn (PR #13) — async-populated symbol annotations.UNIQUE(session_id, input_hash)(PR #12) — kills the SELECT-then-INSERT TOCTOU race.UNIQUE INDEX on summaries(event_id)(PR #8) — enforces one summary per event at the DB layer.
Added — operations¶
mem doctor(PR #11) — integrity, orphans, vec0 cardinality drift, counts, pinned.--heal(PR #12) repairs drift in place.mem prune/mem retry(PR #9) — operational recovery for old skipped events and quota-poisoned queues.mem export/mem import(PR #12) — ndjson snapshot for migration / cross-machine sync.mem searchCLI (PR #12) — one-shot hybrid search wrapper.mem auth-token [--rotate](PR #16) — print or rotate the web UI bearer.- Daemon supervision (PR #9) — pid-aliveness handshake,
uncaughtExceptionlogging,http.portcleanup on shutdown, periodic counter snapshots.
Fixed — correctness¶
- Drain race + cache double-write (PR #8) —
claimPendingwithBEGIN IMMEDIATE+ in-process write lock;INSERT … ON CONFLICT DO NOTHING. - WAL replay actually runs on boot (PR #8) — daemon folds leftover frames back into SQLite, then truncates.
- Retryable error policy (PR #8) — quota / 429 / 5xx / network errors release back to
raw; onlyattempts ≥ 3or terminal errors →skipped. siftcoder list(PR #8) — was returning[]; newsummariesRPC +Storage.recentSummaries.siftcoder check(PR #8) — was emitting two contradictory JSON blobs.parseModelOutputtruncation handling (PR #8) — strips```jsonfences, recovers truncatedtextfield.- vec0 dim now runtime-resolved (PR #10) — was pinned at 384, mismatching nomic-embed-text's 768.
- Storage facade encapsulation (PR #9) — six
(storage as unknown as {db}).dbleak sites collapsed into typed methods. - Prepared-statement cache (PR #9) — capture hot path no longer re-prepares identical SQL.
- UDS multi-frame fix (PR #12) — server no longer closes the connection on partial frames; large requests (10 KB+) split across multiple
dataevents succeed. pg-worker.cjs→.mjsfilename mismatch (PR #9) — was breaking PG bootstrap silently.- Pre-existing CI lint error in
pg-worker.mjs(PR #8) — TS syntax in a.mjsfile unblocked all CI runs after months of failures.
Security¶
- Web auth uses
crypto.timingSafeEqual(PR #8) — was===despite a comment claiming "constant-time comparison". - Gemini API key in header, not URL query (PR #8) — was leaking via proxy logs and exception stacks.
[1.0.9] — 2026-05-02¶
Fixed¶
- Daemon no longer auto-shuts on idle.
src/memory/daemon/index.tshad a hardcodedIDLE_SHUTDOWN_MS = 30 * 60 * 1000that killed the daemon after 30 minutes without a socket connection. In practice this meant a quiet stretch in a Claude Code session (lunch, a meeting, deep reading) silently killed the daemon and subsequentPostToolUsecaptures dropped on the floor until the nextSessionStarthook restarted it. Idle shutdown is now disabled by default. SetSIFTCODER_IDLE_SHUTDOWN_MS=<ms>to opt back in if you really want the cleanup behaviour.
[1.0.8] — 2026-05-02¶
Added¶
siftcoder infoCLI subcommand — full runtime snapshot in one place: package version, plugin manifest version, Node/platform/arch, install root, namespace, workspace key + cwd + git toplevel, daemon state with pid + uptime, socket/db/pid file paths, web URL (when bridge is up), backend availability (Ollama probe, Anthropic key configured), event/summary/embedding counts, and DB size on disk. Supports human-readable default and--jsonfor piping./siftcoder:mem info [--json]— same data, exposed via the existing memory slash command. Also documentsversionas a discrete action.- SiftCoder Field Guide — new long-form documentation site at ialameh.github.io/sift-coder. Built with mkdocs-material, light/dark toggle, full-text search, sticky tab nav, code copy buttons, edit-on-GitHub links. Auto-deploys on every push to
mainvia.github/workflows/docs.yml. Source lives indocs/. Quickstart, Foundations, Operations, Reference, Salesforce, Cookbook, and Project tabs.
[1.0.7] — 2026-05-02¶
Fixed¶
bin/siftcoder.mjs—siftcoder backfillwas broken:rpc('backfill', { source })calledrpc()with two positional args, butrpc()takes a single request object. Daemon received the bare string"backfill", returned nothing, and the CLI crashed withError: short response. Now sendsrpc({ kind: 'backfill', source })and uses a 5-minute timeout (vs. the 5s default) since transcript scans can take a while.- Daemon
backfillRPC was never implemented. Added abackfillcase tosrc/memory/daemon/server.tsthat scans~/.claude/projects/<encoded-cwd>/*.jsonl, parses tool-use frames viareplay.ts, and ingests them through the same WAL + storage path as livecaptureevents. Deduplicates against existing rows by(session_id, input_hash). Returns{ scanned, captured, skippedDuplicate, errors }. src/memory/storage/storage.ts— addedhasEvent(sessionId, inputHash)to support backfill's dedupe check.src/memory/protocol.ts— addedBackfillRequestshape +'backfill'toRequestKind.
Removed¶
- Stale
dist/memory/migration/v2-import.*orphans. The sourcesrc/memory/migration/v2-import.tswas deleted in an earlier release, but the compiled artifacts lingered indist/. No code referenced them.npm run clean && npm run buildremoves them on this release.
[1.0.6] — 2026-05-01¶
Changed¶
- Default namespace renamed
v3→default. Thev3marker (visible insiftcoder statusoutput as"namespace": "v3") was a leftover from internal "third generation" naming during the rebuild and confused public users. State now lives at~/.siftcoder/default/instead of~/.siftcoder/v3/. - Auto-migration on first run.
hooks/session-start/ensure-built.mjschecks for legacy~/.siftcoder/v3/and atomically renames to~/.siftcoder/default/when the new dir doesn't exist. Logsnamespace-migratedevent. Idempotent. No data loss. - Updated 18 file defaults:
bin/,monitors/, all 8 hooks,scripts/setup.mjs,src/core/{config,paths}.ts,src/memory/workspace.ts,.claude-plugin/plugin.json,.mcp.json,settings.json.
Notes¶
- Override via
SIFTCODER_NS=<name>env var still works for users who explicitly want isolation. - If you set
SIFTCODER_NS=v3explicitly, migration is skipped and you stay on the legacy path.
[1.0.5] — 2026-05-01¶
Fixed¶
scripts/setup.mjs— header read literal"SiftCoder v3 setup"(leftover from internal "third generation" naming during the rebuild). Now reads version frompackage.jsonso output matches the public release:SiftCoder v1.0.5 setup. Internal~/.siftcoder/v3/namespace path stays unchanged — it's the state-isolation marker, not the public version.
[1.0.4] — 2026-05-01¶
Hotfix: scripts/setup.mjs crashed with ERR_USE_AFTER_CLOSE when stdin was not a TTY (e.g. running setup via node bin/siftcoder.mjs setup < /dev/null or under any non-interactive pipe). Readline.question fired against a closed stream.
Fixed¶
scripts/setup.mjs— detects non-TTY stdin viaprocess.stdin.isTTY. Skips theANTHROPIC_API_KEYprompt in non-interactive mode and prints a hint to export the env var instead. Writes config either way using whatever's already in the environment. Interactive TTY behaviour unchanged.
[1.0.3] — 2026-05-01¶
Hotfix on top of v1.0.2: the v1.0.2 native-binding probe used require('better-sqlite3') only, which can pass when the binding loads OK but actually fails at the first SQLite call (Node-25 / prebuild-ABI mismatch case). The probe missed the case it was added to catch.
Fixed¶
hooks/session-start/ensure-built.mjs— probe now opens an in-memory DB and runsselect 1to verify the binding works at runtime, not just at load. Catches the load-OK / runtime-broken case. 10s budget. Triggersnpm rebuild better-sqlite3correctly when needed.
[1.0.2] — 2026-05-01¶
Hotfix: on Node majors that ship ahead of better-sqlite3 prebuilt binaries (e.g. Node 25 in 2026), require('better-sqlite3') crashes at module load and the WASM fallback also fails on init. Result: siftcoder status, the daemon, and the MCP server all fall over.
Fixed¶
hooks/session-start/ensure-built.mjs— afternpx tsc, probes the native binding via a 8s subprocessnode -e "require('better-sqlite3')". On failure, runsnpm rebuild better-sqlite3 --silent(180s budget) and re-probes. On second failure, drops an install-error flag with the manual recovery command and logs to~/.siftcoder/v3/logs/install.ndjson(eventsnative-rebuild,native-rebuild-ok,native-rebuild-fail).- Idempotent: probe is fast (~30ms) when binding works; rebuild only fires when needed.
Manual recovery (if auto-rebuild is blocked)¶
! cd ~/.claude/plugins/cache/siftcoder-marketplace/siftcoder/<version> && npm rebuild better-sqlite3
[1.0.1] — 2026-05-01¶
Hotfix: plugin marketplace installs were missing dist/ (clones don't run npm install), so bin/siftcoder.mjs and the MCP server failed with ERR_MODULE_NOT_FOUND on first use.
Fixed¶
hooks/session-start/ensure-built.mjs(NEW) — auto-runsnpm install(if needed) thennpx tscon first session start whendist/memory/mcp/server.jsis missing or stale relative tosrc/. Idempotent. Logs to~/.siftcoder/v3/logs/install.ndjson. Budget 300s on first run, < 50ms on subsequent.hooks/session-start/install-error-banner.mjs(NEW) — surfaces a one-shot user-facing banner with the exact! cd … && npm install && npm run buildcommand ifensure-built.mjsfails. Auto-clears after first display.scripts/postinstall.mjs— also buildsdist/if absent (coversnpm installpaths). Falls back gracefully ifnpx tscfails.bin/siftcoder.mjs— preflightensureBuilt()check onopenStorage()surfaces a clear error message with the exact recovery command instead of an opaqueERR_MODULE_NOT_FOUND.docs/TROUBLESHOOTING.md— new "Install" section documenting the auto-fix + manual command.
Hooks count¶
7 active + 1 opt-in unchanged. SessionStart now chains 3 hooks: ensure-built → spawn-daemon → install-error-banner. All non-blocking.
[1.0.0] — 2026-05-01¶
Initial public release.
Memory engine¶
- Persistent per-workspace memory daemon with UDS RPC, dual SQLite backends (native + WASM), RRF retrieval, Ebbinghaus decay, typed provenance graph (
mem_why). - Local-LLM defaults via Ollama (summarisation + embeddings); Anthropic API as opt-in fallback. ~50× steady-state token-cost reduction.
- MCP server
siftcoder-memoryexposingmem_search,mem_get,mem_timeline,mem_why,mem_drainto Claude Code natively. - Memory daemon health monitor (
monitors/memory-daemon-health.mjs).
Plugin surface¶
- 96 skills across 12 family folders (coding, reasoning, quality, review, knowledge, docs, workflow, spec, salesforce, integrations, ux, meta). Each skill is a workflow contract with method, output shape, hard rules, anti-patterns, when-NOT-to-use, and value-add over native Claude Code.
- 107 slash commands — thin wrappers + multi-verb consolidations like
/siftcoder:mem [start|status|drain|setup|web|backfill]. - 15 agents — 4 Salesforce-domain (
salesforce-architect,apex-bulkifier,lwc-debugger,memory-curator) plus 11 disciplined generics (planner,coder,qa-reviewer,qa-fixer,reviewer,documenter,tester,investigator,orchestrator,analyst,bridge-analyzer). - 7 hooks under
hooks/<event>/<name>.mjs:boundary-enforcer(PreToolUse),capture-observation+detect-console-logs(PostToolUse),inject-memories(PreCompact),pin-incident(Notification),spawn-daemon(SessionStart),should-continue(Stop). Plus opt-inauto-checkpoint(disabled by default). - 1 monitor — 30s UDS ping + ndjson health log.
Salesforce¶
- Domain skills:
salesforce-apex,salesforce-lwc,salesforce-deploy,salesforce-architecture,salesforce-test,salesforce-flow,salesforce-cpq,salesforce-agentforce,salesforce-einstein,salesforce-security,salesforce-comply,schema-migrate. - Domain agents:
salesforce-architect(read-only architecture review),apex-bulkifier(targeted bulk-safety refactor),lwc-debugger(LWC issue diagnosis). - Webhook scaffold (
/siftcoder:sf-webhook) ships with HMAC verification and timestamp window by default.
Tooling¶
- CLI at
bin/siftcoder.mjs—setup,start,stop,status,drain,backfill,web,version. - Plugin
settings.jsonwith safe defaults for hook timeouts, drain backend cascade, embedder cascade, retention windows. - GitHub Actions CI — matrix across ubuntu/macos/windows × Node 20/22.
- ESLint + Prettier + TypeScript strict + Vitest baseline.
- Coverage gate: 96% lines, 98% branches/functions across the memory engine.
Security¶
- Boundary enforcer hook reads scope from
.siftcoder/scope.jsonand blocks Write/Edit outside listed allow-globs. - Local-only data path: capture stays on disk; drain through Ollama keeps payloads on the user's machine.
- PII redaction at hook edge (8 built-in patterns: AWS / GitHub / Anthropic / OpenAI / Bearer / JWT / email / phone).
- Web bridge bound to 127.0.0.1 only; bearer token at
~/.siftcoder/auth.token(mode 0600).