Pipeline configuration
Pipeline V2 Config
Section titled “Pipeline V2 Config”The V2 memory pipeline lives at platform/daemon/src/pipeline/. It runs
LLM-based fact extraction against incoming conversation text, then decides
whether to write new memories, update existing ones, or skip. Config lives
under memory.pipelineV2 in agent.yaml.
Inference selection for extraction can be routed through the top-level
inference.workloads bindings. Session processing follows the
memoryExtraction route and is not independently configurable. When explicit routing is
enabled for default, memoryExtraction, widgetGeneration, or repair, those workloads use the
shared inference control plane. Legacy extraction and synthesis fields are treated as load-time compatibility input, not separate runtime providers.
The config uses a nested structure with grouped sub-objects. Legacy flat
keys (e.g. extractionModel, leaseTimeoutMs) are still supported for
backward compatibility, but nested keys take precedence when both are
present.
Enable the pipeline:
memory: pipelineV2: enabled: true shadowMode: true # extract without writing — safe first step extraction: provider: llama-cpp model: qwen3:4bControl flags
Section titled “Control flags”These top-level boolean fields gate major pipeline behaviors.
| Field | Default | Description |
|---|---|---|
enabled |
true |
Master switch. Pipeline does nothing when false. |
shadowMode |
false |
Extract facts but skip writes. Useful for evaluation. |
mutationsFrozen |
false |
Allow reads; block all writes. Overrides shadowMode. |
semanticContradictionEnabled |
true |
Enable LLM-based semantic contradiction detection for UPDATE/DELETE proposals. |
telemetryEnabled |
true |
Enable anonymous telemetry reporting (set false to opt out). |
The relationship between shadowMode and mutationsFrozen matters:
shadowMode suppresses writes from the normal extraction path only;
mutationsFrozen is a harder freeze that blocks all write paths
including repairs and graph updates.
Extraction (extraction)
Section titled “Extraction (extraction)”Controls the LLM-based extraction stage. Supports multiple providers.
| Field | Default | Range | Description |
|---|---|---|---|
provider |
"llama-cpp" |
— | "none", "acpx", "llama-cpp", "ollama", "claude-code", "opencode", "codex", "anthropic", "openrouter", "openai-compatible", or "command" |
fallbackProvider |
"llama-cpp" |
— | "llama-cpp", "ollama", or "none"; legacy extraction configs compile this into an inference fallback target |
model |
"qwen3:4b" |
— | Model name for the configured provider |
timeout |
90000 |
5000-300000 ms | Extraction call timeout |
minConfidence |
0.7 |
0.0-1.0 | Confidence threshold; facts below this are dropped |
structuredOutput |
true |
— | Send JSON schema in the format field of LLM requests. Set false when the provider rejects structured output (e.g. GitHub Copilot API). The daemon also auto-detects unsupported providers at runtime and disables this transparently. |
command |
— | — | Command provider config (bin, args[], optional cwd, optional env) — required when provider: "command" |
rateLimit.maxCallsPerHour |
200 when rateLimit is set |
0-10000 | Max extraction-provider calls per hour; set 0 to disable rate limiting |
rateLimit.burstSize |
20 when rateLimit is set |
1-1000 | Max burst size before throttling begins |
rateLimit.waitTimeoutMs |
5000 when rateLimit is set |
0-60000 ms | How long to wait for a token before failing with RateLimitExceededError |
For provider: openai-compatible, set endpoint to the gateway’s
OpenAI-compatible /v1 base URL. Remote endpoints use OPENAI_API_KEY by
default when this legacy pipeline config is compiled into inference routing;
explicit top-level inference.accounts.*.credentialRef can point at any
stored secret or environment variable.
For safety, the intended extraction setups are:
- local
llama-cppwithqwen3:4b(default) claude-codeon a Haiku modelcodexon a gpt-5.4-mini model- local
ollamawithnemotron-3-nano:4b(preferred) orqwen3:4b(deprecated — Nemotron’s superior reasoning makes Qwen3 the weaker choice going forward; expect degraded extraction quality in future updates)
Set provider: none to disable extraction entirely, which is the
recommended default for VPS installs that should not make background LLM
calls.
Remote API extraction can accumulate extreme fees quickly because the
pipeline runs continuously in the background. Use anthropic,
openrouter, openai-compatible, or remote OpenCode routes only when you explicitly want
that billing behavior.
rateLimit is opt-in. If the stanza is omitted, Signet preserves the
provider’s existing behavior with no throughput throttling. When
configured, it applies only to remote or paid providers
(acpx, claude-code, anthropic, openrouter, openai-compatible, codex, opencode).
Ollama and command providers are always exempt. If you set rateLimit
on an exempt provider, Signet logs a warning and passes calls through
unthrottled.
An empty rateLimit: {} block is treated as disabled. Set at least one
sub-field to opt in, or omit the stanza entirely to leave rate limiting
off.
When a rate-limited job fails (the bucket is empty and the wait timeout
expires), it is classified as non-retryable and sent directly to
dead-letter status. Dead-lettered jobs are not retried when the rate-limit
window resets. Choose maxCallsPerHour high enough to handle sustained
ingestion bursts, or you will permanently lose extraction for memories
queued during exhaustion. Dead-letter jobs are purged after 30 days by
the retention worker.
When configured via YAML, burstSize is clamped to a minimum of 1.
The lower-level withRateLimit() helper is more defensive: passing
burstSize: 0 or maxCallsPerHour: 0 disables the wrapper entirely
instead of constructing a limiter that can never acquire a token.
Rate-limiter state is in-memory only. After a daemon restart the full
burstSize is available immediately (the token bucket starts full). In
environments with frequent restarts (crash-loops, rolling deployments),
this means the limiter cannot protect against a burst of calls right
after startup. Set burstSize conservatively if your daemon restarts
often under load.
When using ollama, the model must be available locally. When using
claude-code, the Claude Code CLI must be on PATH. codex uses the
Codex CLI as the extraction provider. Lower minConfidence to capture
more facts at the cost of noise; raise it to write only high-confidence
facts.
acpx is available as a setup compatibility value for installations that also
have a top-level inference: block. ACPX needs harness/session config, so
legacy memory.pipelineV2.extraction.provider: acpx by itself is not compiled
into an implicit legacy-extraction target; keep the generated
inference.targets.*.executor: acpx block or configure ACPX through top-level
inference routing.
There are two command paths with different contracts. Top-level
inference.targets.*.executor: command is a normal inference provider: the
prompt is sent on stdin, exposed as SIGNET_PROMPT, and the model response is
read from stdout.
memory.pipelineV2.extraction.provider: command is retired. It is rejected at
config load time; use the canonical inference.workloads.memoryExtraction
target consumed by Dreaming instead. The retired path let a subprocess write
memory state outside the daemon-owned audited apply path.
Session synthesis (synthesis)
Section titled “Session synthesis (synthesis)”Controls the provider used by the summary-worker for session summaries.
This is separate from fact extraction once explicitly configured.
If the synthesis block is omitted entirely, Signet falls back to the
resolved extraction provider, model, endpoint, and timeout. When an explicit
top-level inference: block exists, workload bindings decide which target
handles synthesis.
| Field | Default | Range | Description |
|---|---|---|---|
enabled |
true |
— | Enable background session summary generation |
provider |
inherited from extraction when omitted | — | "none", "llama-cpp", "ollama", "claude-code", "codex", "opencode", "anthropic", "openrouter", or "openai-compatible" |
model |
inherited from extraction when omitted | — | Model name for the configured provider |
endpoint |
inherited from extraction when omitted | — | Optional base URL override for Ollama, OpenCode, OpenRouter, or OpenAI-compatible gateways |
timeout |
inherited from extraction when omitted | 5000-300000 ms | Summary generation timeout |
structuredOutput |
inherited from extraction when omitted | — | Send JSON schema in the format field of LLM requests. Set false when the synthesis provider rejects structured output (e.g. GitHub Copilot API). Falls back to extraction.structuredOutput when omitted. |
rateLimit.maxCallsPerHour |
200 when rateLimit is set |
0-10000 | Max synthesis-provider calls per hour; set 0 to disable rate limiting |
rateLimit.burstSize |
20 when rateLimit is set |
1-1000 | Max burst size before throttling begins |
rateLimit.waitTimeoutMs |
5000 when rateLimit is set |
0-60000 ms | How long to wait for a token before failing with RateLimitExceededError |
Set provider: none or enabled: false to disable background session
summary synthesis entirely.
synthesis.provider: command is invalid and rejected during config load.
Widget HTML generation uses a separate provider instance by default, so
widget traffic does not consume the synthesis pipeline’s rateLimit
bucket.
As with extraction, an empty rateLimit: {} block is treated as
disabled. Set at least one sub-field to opt in.
Rate-limited synthesis jobs that fail are sent to dead-letter without
retry. See the extraction rateLimit docs above for the full warning.
Claude Code background environment (claudeCode)
Section titled “Claude Code background environment (claudeCode)”Applies whenever legacy pipeline extraction, synthesis, or an explicit
inference route uses the claude-code provider.
| Field | Default | Range | Description |
|---|---|---|---|
allowApiKeyEnv |
false |
— | When false, daemon-spawned claude -p calls strip ambient ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN. Set true only when background pipeline jobs should inherit those env credentials. Legacy unshipped billingMode: api-key is accepted as an alias for true; billingMode: subscription maps to false. |
maxBudgetUsd |
unset | 0.01-1000 | Optional per-invocation spend cap passed to Claude Code print mode as --max-budget-usd. Omitted by default because Claude Code documents no default limit for this flag and forcing one could change CLI behavior. |
cooldownMs |
300000 |
1000-3600000 ms | Daemon-wide Claude Code circuit cooldown opened after Claude Code reports quota, usage-limit, credit, billing, or auth failures. Calls during cooldown fail before spawning claude. Interactive and background claude-code providers in the daemon share this circuit and config snapshot. |
memory: pipelineV2: claudeCode: allowApiKeyEnv: false cooldownMs: 300000Only opt into ambient API-key/token inheritance when you intentionally want background pipeline jobs to use the Anthropic credentials already present in the daemon environment:
memory: pipelineV2: claudeCode: allowApiKeyEnv: true maxBudgetUsd: 0.25Anthropic’s Claude Code CLI reference lists --max-budget-usd as a
print-mode-only API-call budget flag:
https://docs.anthropic.com/en/docs/claude-code/cli-reference. Anthropic’s
Claude Code cost docs describe Claude Code charges in terms of API token
consumption and subscription plan pricing separately:
https://docs.anthropic.com/en/docs/claude-code/costs. Anthropic support docs
also state that paid Claude subscriptions and Claude Console/API usage are
separate products:
https://support.anthropic.com/en/articles/9876003-i-subscribe-to-claude-pro-why-do-i-have-to-pay-separately-for-api-usage-on-console.
Signet does not verify the billing account selected by a persisted
claude auth login --console session; it only controls whether the daemon
subprocess inherits ambient Anthropic API key/token environment variables.
Worker (worker)
Section titled “Worker (worker)”The pipeline processes jobs through a queue with lease-based concurrency control.
| Field | Default | Range | Description |
|---|---|---|---|
maxRetries |
3 |
1-10 | Max retry attempts before a job goes to dead-letter |
leaseTimeoutMs |
300000 |
10000-600000 ms | Time before an uncompleted job lease expires |
maxLlmConcurrency |
2 |
1-16 | Shared cap for live LLM calls across extraction, synthesis, reranking, inference streaming, and daemon route provider calls such as skills, ontology consolidation, and diagnostics greetings. SIGNET_MAX_LLM_CONCURRENCY overrides YAML when set, matching the TypeScript daemon behavior for wired provider paths. |
A job that exceeds maxRetries moves to dead-letter status and is
eventually purged by the retention worker.
The standalone extraction worker was retired under the Dreaming cutover
(#946); its former pollMs, maxLoadPerCpu, overloadBackoffMs, and
threadedExtraction knobs are no longer read from configuration (legacy
YAML values are ignored).
Knowledge Graph (graph)
Section titled “Knowledge Graph (graph)”When graph.enabled: true, the pipeline builds entity-relationship links
from extracted facts and uses them to boost search relevance.
| Field | Default | Range | Description |
|---|---|---|---|
enabled |
true |
— | Enable knowledge graph building and querying |
boostWeight |
0.15 |
0.0-1.0 | Weight applied to graph-neighbor score boost |
boostTimeoutMs |
500 |
50-5000 ms | Timeout for graph lookup during search |
Hints (hints)
Section titled “Hints (hints)”Prospective indexing generates hypothetical future queries at write time. These “hints” are indexed in FTS5 so memories match by anticipated cue, not just stored content. For example, a memory about “switched from PostgreSQL to SQLite” might generate hints like “database migration”, “why SQLite”, and “storage engine decision” — queries the user is likely to ask later.
| Field | Default | Range | Description |
|---|---|---|---|
enabled |
true |
— | Enable prospective indexing |
max |
5 |
1-20 | Maximum hints generated per memory |
timeout |
30000 |
5000-120000 ms | Hint generation LLM timeout |
maxTokens |
256 |
32-1024 | Max tokens for hint generation |
poll |
5000 |
1000-60000 ms | Job polling interval |
memory: pipelineV2: hints: enabled: true max: 5 timeout: 30000 maxTokens: 256 poll: 5000Traversal (traversal)
Section titled “Traversal (traversal)”Graph traversal controls how the knowledge graph is walked during
retrieval. When primary: true, graph traversal produces the base
candidate pool and flat search fills gaps. When primary: false,
traditional hybrid search runs first with graph boost as
supplementary.
| Field | Default | Range | Description |
|---|---|---|---|
enabled |
true |
— | Enable graph traversal |
primary |
true |
— | Use traversal as primary retrieval strategy |
maxAspectsPerEntity |
20 |
1-50 | Max aspects to collect per entity (read cap) |
maxAttributesPerAspect |
50 |
1-100 | Max attributes per aspect (read cap) |
maxWriteAspectsPerEntity |
20 |
1-50 | Max active aspects per entity before create_aspect is rejected |
maxWriteAttributesPerAspect |
50 |
1-100 | Max active attributes per aspect before add_claim_value is rejected |
maxDependencyHops |
10 |
1-50 | Max hops for dependency walking |
minDependencyStrength |
0.3 |
0.0-1.0 | Minimum edge strength to follow |
maxBranching |
4 |
1-20 | Max branching factor during traversal |
maxTraversalPaths |
50 |
1-500 | Max paths to explore |
minConfidence |
0.5 |
0.0-1.0 | Minimum confidence for results |
timeoutMs |
500 |
50-5000 ms | Traversal timeout |
boostWeight |
0.2 |
0.0-1.0 | Weight for traversal boost in hybrid search |
constraintBudgetChars |
1000 |
100-10000 | Character budget for constraint injection |
memory: pipelineV2: traversal: enabled: true primary: true maxAspectsPerEntity: 20 maxAttributesPerAspect: 50 maxWriteAspectsPerEntity: 20 maxWriteAttributesPerAspect: 50 maxDependencyHops: 10 minDependencyStrength: 0.3 maxBranching: 4 maxTraversalPaths: 50 minConfidence: 0.5 timeoutMs: 500 boostWeight: 0.2 constraintBudgetChars: 1000The primary flag determines the retrieval strategy. In primary mode,
entities are extracted from the query, the graph is walked to collect
related memories, and flat hybrid search only runs to fill remaining
slots. In supplementary mode (primary: false), the standard hybrid
search runs first and traversal results are blended in using
boostWeight. Primary mode is faster for entity-dense queries;
supplementary mode is more conservative and better for freeform text.
Reranker (reranker)
Section titled “Reranker (reranker)”An optional reranking pass that runs after initial retrieval. An embedding-based reranker is built in (uses cached vectors, no extra LLM calls). Optionally, reranking can call the active extraction provider model.
| Field | Default | Range | Description |
|---|---|---|---|
enabled |
true |
— | Enable the reranking pass |
model |
"" |
— | Model name for the reranker (empty uses embedding-based) |
useExtractionModel |
false |
— | When true, use the extraction provider LLM for reranking and emit a synthesized summary card |
topN |
20 |
1-100 | Number of candidates to pass to the reranker |
timeoutMs |
2000 |
100-30000 ms | Timeout for the reranking call |
Autonomous (autonomous)
Section titled “Autonomous (autonomous)”Controls autonomous maintenance, repair, and mutation behavior.
| Field | Default | Description |
|---|---|---|
enabled |
true |
Allow autonomous pipeline operations (maintenance, repair). |
frozen |
false |
Block autonomous writes; autonomous reads still allowed. |
allowUpdateDelete |
true |
Permit the pipeline to update or delete existing memories. |
maintenanceIntervalMs |
1800000 |
How often maintenance runs (30 min). Range: 60s-24h. |
maintenanceMode |
"execute" |
"observe" logs issues; "execute" attempts repairs. |
In "observe" mode the worker emits structured log events but makes no
changes. When frozen is true, the maintenance interval never starts,
though the worker’s tick() method remains callable for on-demand
inspection.
Repair budgets (repair)
Section titled “Repair budgets (repair)”Repair sub-workers limit how aggressively they re-embed, re-queue, or deduplicate items to avoid overloading providers.
| Field | Default | Range | Description |
|---|---|---|---|
reembedCooldownMs |
300000 |
10s-1h | Min time between re-embed batches |
reembedHourlyBudget |
10 |
1-1000 | Max re-embed operations per hour |
requeueCooldownMs |
60000 |
5s-1h | Min time between re-queue batches |
requeueHourlyBudget |
50 |
1-1000 | Max re-queue operations per hour |
dedupCooldownMs |
600000 |
10s-1h | Min time between dedup batches |
dedupHourlyBudget |
3 |
1-100 | Max dedup operations per hour |
dedupSemanticThreshold |
0.92 |
0.0-1.0 | Cosine similarity threshold for semantic dedup |
dedupBatchSize |
100 |
10-1000 | Max candidates evaluated per dedup batch |
Document ingest (documents)
Section titled “Document ingest (documents)”Controls chunking for ingesting large documents into the memory store.
| Field | Default | Range | Description |
|---|---|---|---|
workerIntervalMs |
10000 |
1s-300s | Poll interval for pending document jobs |
chunkSize |
2000 |
200-50000 | Target chunk size in characters |
chunkOverlap |
200 |
0-10000 | Overlap between adjacent chunks (chars) |
maxContentBytes |
10485760 |
1 KB-100 MB | Max document size accepted |
Chunk overlap ensures context is not lost at chunk boundaries. A value of
10-15% of chunkSize is a reasonable starting point.
Guardrails (guardrails)
Section titled “Guardrails (guardrails)”Content size limits applied during extraction and recall to prevent oversized content from degrading pipeline performance.
| Field | Default | Range | Description |
|---|---|---|---|
maxContentChars |
500 |
50-100000 | Max characters stored per memory |
chunkTargetChars |
300 |
50-50000 | Target chunk size for content splitting |
recallTruncateChars |
500 |
50-100000 | Max characters returned per memory in recall results |
These limits are enforced at the pipeline level. Content exceeding
maxContentChars is truncated before storage. Recall results are
truncated at recallTruncateChars to keep session context budgets
predictable.
Continuity (continuity)
Section titled “Continuity (continuity)”Session checkpoint configuration for continuity recovery. Checkpoints capture periodic snapshots of session state (focus, prompts, memory activity) to aid recovery after context compaction or session restart.
| Field | Default | Range | Description |
|---|---|---|---|
enabled |
true |
— | Master switch for session checkpoints |
promptInterval |
10 |
1-1000 | Prompts between periodic checkpoints |
timeIntervalMs |
900000 |
60s-1h | Time between periodic checkpoints (15 min default) |
maxCheckpointsPerSession |
50 |
1-500 | Per-session checkpoint cap (oldest pruned) |
retentionDays |
7 |
1-90 | Days before old checkpoints are hard-deleted |
recoveryBudgetChars |
2000 |
200-10000 | Max characters for recovery digest |
Checkpoints are triggered by five events: periodic, pre_compaction,
session_end, agent, and explicit. Secrets are redacted before
storage.
Sub-agents (subagents)
Section titled “Sub-agents (subagents)”Controls deterministic parent-session context inherited by sub-agent sessions
at session-start. This uses stored active transcripts and checkpoints; it
does not make an LLM call.
| Field | Default | Range | Description |
|---|---|---|---|
inheritContext |
true |
— | Inject a compact parent context block when parent lineage is available |
tailChars |
3000 |
0-20000 | Max transcript tail characters included from the parent session |
memory: pipelineV2: subagents: inheritContext: true tailChars: 3000Set inheritContext: false to disable automatic inherited context while
leaving the explicit session_search MCP/API surface available.
Telemetry (telemetry)
Section titled “Telemetry (telemetry)”Anonymous usage telemetry. On by default; set telemetryEnabled: false
to opt out. Events are batched and flushed periodically. Sending requires
both posthogHost and posthogApiKey. Each install gets a random
anonymous id (persisted in the workspace database) used as the PostHog
distinct_id, so installs stay countable without being identifiable.
See TELEMETRY.md — the single reference for the
event catalog, privacy contract, the open JSONL audit log, runtime opt-out
(SIGNET_TELEMETRY_OPTOUT=1), and how to query the data.
Disclosure (issue #1026): signet setup tells users telemetry is on
by default and asks whether to disable it. Declining writes
telemetryEnabled: false; non-interactive/CI setups keep the default
(enabled).
Runtime opt-out: setting SIGNET_TELEMETRY_OPTOUT=1 in the daemon’s
environment disables telemetry without touching config — the same knob the
install ping honors. CI runners, containers, and scripted environments
should set it so automated daemon boots don’t count as installs.
Open telemetry log: every recorded event is appended as one JSON line
to <agentsDir>/.daemon/telemetry/events.jsonl — the single inspectable
audit surface for exactly what was sent (daemon events and CLI
command.invoked lines). CLI command events are also queued in the workspace
database and flushed to PostHog in bounded, best-effort batches without
awaiting the command. The CLI and daemon use the same persisted install id.
No memory content, code, file paths, or personal
data are ever included.
Lifecycle events: daemon.started (version, platform,
uptime), command.invoked (command name only, never arguments),
error.occurred (sanitized crash report — truncated message with user paths
stripped, top stack frames with home directories removed, uptime, and
rate-limited EventLoopLag reports with measured lag), version.upgraded
(from, to).
Development fleet marker: setting SIGNET_TELEMETRY_ENV=dev keeps operator
development checkouts in the dataset while making them filterable. The daemon
adds deployment: dev to its local and PostHog events, while the CLI adds it
to its JSONL-only command events. The native install ping applies the marker
and -dev version suffix when the environment is present. The daemon and CLI
bun run dev scripts set this marker automatically. The marker does not
disable telemetry; use SIGNET_TELEMETRY_OPTOUT=1 when development or
automated events should be silenced entirely.
| Field | Default | Range | Description |
|---|---|---|---|
posthogHost |
https://us.i.posthog.com |
— | PostHog instance URL (empty disables) |
posthogApiKey |
phc_mLsvJmbmp6e9UarrX9Cq5QtTjVNiiphM9mvi5Xnddd8Q |
— | PostHog project API key. Public ingest key by design; shared by daemon and CLI |
flushIntervalMs |
60000 |
5s-10min | Time between event flushes |
flushBatchSize |
50 |
1-500 | Max events per flush batch |
retentionDays |
90 |
1-365 | Days before local telemetry data is purged |
memorySearchQaEnabled |
false |
boolean | Capture local-only recall QA rows with query text and result snapshots |
memorySearchQaEnabled is separate from anonymous telemetry. It writes a
local review ledger to SQLite and intentionally includes recall query text
and recalled result content, so it is exposed only through analytics-gated
endpoints and is never sent to PostHog.
Embedding tracker (embeddingTracker)
Section titled “Embedding tracker (embeddingTracker)”Background polling loop that detects stale or missing embeddings and refreshes them in small batches. Runs alongside the extraction pipeline.
| Field | Default | Range | Description |
|---|---|---|---|
enabled |
true |
— | Master switch |
pollMs |
5000 |
1s-60s | Polling interval between refresh cycles |
batchSize |
8 |
1-20 | Max embeddings refreshed per cycle |
The tracker detects embeddings that are missing, have a stale content
hash, or were produced by a different model than the currently configured
one. It uses setTimeout chains for natural backpressure.