Source resolution¶
See the protocol spec for normative requirements.
theta CLI
theta lock resolves and pins all sources. theta lock --force re-resolves unconditionally.
Source types¶
Source types vary by resource kind:
Rules (LocalOrGitRef)¶
| Source | Syntax | Resolution |
|---|---|---|
| Local | "rules/my-rule.md" (bare string) |
Relative path to a .md file |
| Git | { git = "https://...", tag = "v1.0", file = "rule.md" } |
Single file from a git repo |
| System | { system = "name" } |
Named rule in the system store |
Skills (SourceRef)¶
| Source | Syntax | Resolution |
|---|---|---|
| Path | { path = "./local/dir" } |
Local directory containing SKILL.md |
| Git | { git = "https://...", tag = "v1.0", subdirectory = "skills/x" } |
Directory (or subdirectory) from a git repo |
| System | { system = "name" } |
Named skill in the system store |
Subagents¶
Subagents use agent_ref — a path to a sibling theta.toml. Subagent sources are resolved recursively during locking.
System store¶
The system source references resources registered in the user's local system store. Resolved during locking by content hash, same as path sources.
The store location MUST follow XDG Base Directory conventions. The default resolves to $XDG_DATA_HOME/theta/store/ (Linux) or the platform equivalent on macOS / Windows. Implementations SHOULD respect a THETA_DATA_DIR environment variable override that points to the parent data directory (the store lives at <THETA_DATA_DIR>/store/).
theta CLI
theta register skill|rule|agent adds resources to the store. theta list store lists registered entries. theta rm store <kind> <name> unregisters.
Template / placeholder rejection. theta register rejects skills, rules, and agents whose content is the unedited scaffold template (e.g. SKILL.md containing the default name/description placeholders, or theta.toml with the placeholder description). The store is for finished, reusable resources — templates must be edited first.
theta init --from <name> seeds a new agent from a registered system agent. The CLI copies the registered manifest, system prompt, rules, and skill directories into the new project and rewrites local rule src paths to the project-relative locations. Git-sourced rules and skills are copied verbatim (still resolved from their remote on the next theta lock).
Lockfile¶
theta.lock pins the full dependency graph:
[meta]
schema = "2026-04"
manifest_hash = "sha256:..."
[instructions.system]
source = { path = "system.md" }
content_hash = "sha256:..."
[instructions.rules.my-rule]
source = { path = "rules/my-rule.md" }
content_hash = "sha256:..."
[skills.my-skill]
source = { path = "skills/my-skill" }
content_hash = "sha256:..."
The lockfile MUST be deterministic: same theta.toml produces the same theta.lock. The lockfile MUST be committed to version control.
Forward-declared lock variants
The lockfile schema reserves url = "..." and { registry, name, version } source shapes for future use. They are not produced by any current source type and implementations MAY parse but MUST NOT rely on them. The serialized lock schema may add support without bumping the manifest schema version.
Staleness detection¶
The lock is stale when:
manifest_hashdoes not match the currenttheta.toml- Any local-path or system-sourced dependency has changed on disk
Git sources are never re-checked locally — they are locked by commit SHA.
theta sync re-locks automatically when stale. theta lock --force re-locks unconditionally.
Atomic writes¶
theta CLI
Lockfile writes use a write-to-temp + rename pattern for atomicity.
Local cache¶
Resolved remote dependencies MUST be cached following XDG Base Directory conventions:
- Default:
$XDG_CACHE_HOME/theta/(resolves to~/.cache/theta/on Linux withoutXDG_CACHE_HOMEset; platform-equivalent locations on macOS and Windows viaetcetera) - Git fetches are stored under
<cache>/git/ - MCP registry responses under
<cache>/registry/
Caching SHOULD be content-addressed where possible.