Skip to content

Reference

Pod kinds

A pod kind is a contract. It declares how facts in that kind of pod behave during retrieval, and the engine reads the contract rather than hard-coding behaviour per type.

Terminal window
sigil kind list
sigil kind show project
FieldTypeMeaning
namestringThe kind’s id, stored as pod_type
descriptionstringHuman-readable
identityFieldstring | nullWhat makes a pod of this kind unique. null for virtual kinds.
attrsSchemaobjectTyped attributes the pod carries
visibilityprivate · shared · publicDefault reach for facts in this kind
activeModesee belowHow Sigil decides the pod is live right now
hotContextBudgetnumberSlots in the hot-context blend
retrievalWeights{recency, relevance}How ranking balances the two for this kind
importanceDefaultnumberDefault importance for facts written here
ttlDaysnumber | nullDecay. null = never.
writePolicyorigin-only · openWhether other installs may write to this pod
resolveActiveScopeasync fnReturns the pod uids that are active for a given context
fetchFactsasync fn (optional)Custom retrieval, bypassing the membership join. Used by virtual kinds.
ModeMeaning
singleton-liveExactly one active at a time
multi-activeSeveral can be active simultaneously
rolling-windowActive if touched within a time window
alwaysAlways active

One pod per Claude Code session.

Identitysession_id from the hook envelope
Active modesingleton-live
Hot slots6
Weightsrecency 1.0, relevance 0.7
Importance default2
TTL90 days
Visibilityprivate
Write policyorigin-only

Attributes: session_id, transcript_path, cwd, turn_count, model, conclusion, summary.

Opens on the first hook fire, closes on SessionEnd — or after six hours of cursor inactivity. Weighted heavily toward recency, because within a session what you said five minutes ago matters more than what you said at the start.

When a session ends, its summary attaches to both this pod and the project pod. The session copy expires at 90 days; the project copy is durable.

Terminal window
sigil session current
sigil session list --limit=10
sigil session show <uid>

One pod per code project.

Identityroot_path — but keyed on the normalized git remote when there is one
Active modemulti-active
Hot slots4
Weightsrecency 0.6, relevance 1.0
Importance default3
TTLnever
Visibilityshared
Write policyorigin-only

Attributes: root_path, git_root, git_remote, display_name, discovered_at.

Remote-first identity is the important detail. A path is only meaningful on the machine that holds it — your laptop’s /Users/you/work/api and a cloud agent’s /workspace/api are one project. Keying on remote makes them one pod; keying on path gives two that can never see each other. Path remains the fallback for remote-less local repos, which really are per-machine.

Weighted toward relevance rather than recency: project knowledge is durable, and an architecture decision from a year ago is as true as one from yesterday.


One pod per person you have a working relationship with.

Identityprimary_handle — Slack user id → GitHub username → email
Active moderolling-window (24 hours)
Hot slots4
Weightsrecency 1.0, relevance 0.8
Importance default3
TTLnever
Visibilityprivate
Write policyorigin-only

Attributes: platforms, role, relationship, notes.

Backed by a canonical person entity, so deduplication churn in the graph doesn’t lose their metadata. Handle-first identity means partial-unique upserts on the dominant platform work.

Terminal window
sigil pod create --type=person --name="Priya Nair" \
--github=priyan --email=priya@example.com \
--role="Staff engineer, platform" --relationship=peer

Procedural memory — how you do something.

Identityslug
Active modealways, filtered by matching project
Hot slots3
Weightsrecency 0.3, relevance 1.0
Importance default3
TTLnever
Visibilityshared
Write policyorigin-only

Attributes: slug, project, description, tags.

Surfaces when the active project pod matches the playbook’s project attribute. The deploy runbook for one repo is invisible in every other.

Recency is weighted very low — a runbook doesn’t get less true with age.


Virtual — no row in the pod table.

Identitynone
Active modealways
Hot slots6
Weightsrecency 0.5, relevance 1.0
Importance default5
TTLnever
Visibilitypublic
Write policyopen

A retrieval-time facet rather than a container: facts marked importance=vital surface globally, independent of pod membership. Implemented with a custom fetchFacts, so it skips the membership join entirely.

Visibility is still checked. The kind being “public” means a vital fact isn’t confined to a pod — which is a different question from which agent it was addressed to. This is the path that most needs the check: an assistant-directed instruction is exactly the kind of thing the extractor marks vital, and unscoped, “call me sir” told to one agent would reach all of them.


Virtual. Standing instructions about how to work with you, injected regardless of what the current prompt is about.

Active modealways
Hot slotsreserved, taken before vital
SelectionBy category, not by pod membership

Selected categories: the personal categories minus experience, plus convention.

  • preference, opinion, personal — how you like to work
  • convention — naming rules and team standards; directives even though they’re filed as knowledge
  • not experience — projects built and skills acquired are biography, not instruction
  • not workflow — here it means process flows and state transitions, which would flood the slots with off-project noise

Recall is query-driven. The hook searches with your literal prompt, so a fact surfaces only when it resembles what was just asked. That works for subject-matter facts and fails completely for standing instructions: “keep explanations short” is relevant to every answer and semantically similar to almost no prompt.

The hot-context block is the query-independent channel that fixes it — but its always-on slots used to belong to vital, which is pod-blind and, because the fast path stamps remembered facts as vital, effectively unfiltered. In practice the six slots filled with whatever had been ingested most recently, from any project. Directives never got in.

So directives get their own reserved budget, taken first. A user-level instruction outranks project trivia for the scarcest space in the system.


Registration order in the kind registry is hot-context blend order:

directive → vital → claude_session → project → person → playbook

Each kind contributes up to its budget, with content-level deduplication, capped at 20 facts. Budgets are quotas, not guarantees — a kind with nothing to contribute yields its slots.


A new kind is a contract file plus a registration. No schema migration: pods are rows in one table discriminated by pod_type, and the hot-context blend iterates the registry rather than naming kinds.

export const slackChannelKind = {
name: 'slack_channel',
description: 'A Slack channel you participate in',
identityField: 'channel_id',
attrsSchema: { channel_id: 'string', workspace: 'string', topic: 'string' },
visibility: 'shared',
activeMode: 'rolling-window',
hotContextBudget: 2,
retrievalWeights: { recency: 1.0, relevance: 0.8 },
importanceDefault: 2,
ttlDays: 180,
writePolicy: 'origin-only',
resolveActiveScope: async (ctx) => { /* uids active for this context */ },
};

Register it in src/memory/pods/kinds/index.js. Position in that file decides its place in the blend.

Contracts live in src/memory/pods/kinds/, each with a .schema.md documenting its attributes.