Python bindings for the theta CLI.
uv add theta-py
pip install theta-py
The main surface. Owns a materialized theta project in a temp directory.
The equivalent of this CLI workflow:
theta init
theta add rule python-types
theta add tool fetch --command "uvx mcp-server-fetch"
theta add tool context7 --command "npx -y @upstash/context7-mcp@latest"
theta add skill vercel-labs/agent-skills/skills/web-design-guidelines@main
theta check
theta cast to claude-code
is this:
from theta_py import ThetaProject
with ThetaProject.create(name="my-agent") as proj:
proj.add.rule("python-types")
proj.add.tool("fetch", command="uvx mcp-server-fetch")
proj.add.tool("context7", command="npx -y @upstash/context7-mcp@latest")
proj.add.skill("vercel-labs/agent-skills/skills/web-design-guidelines@main")
proj.check() # raises ThetaCommandError on validation errors
proj.cast.to("claude-code") # --> CLAUDE.md + .mcp.json + .claude/
proj.sync()
print(proj.name) # str
print(proj.system_prompt) # str | None
print(proj.rules) # dict[str, MaterializedRule]
print(proj.skills) # dict[str, MaterializedSkill] — .path is the materialized dir
print(proj.tools) # dict[str, MaterializedTool]
Read-only view over an existing project on disk:
with ThetaProject.from_manifest("path/to/theta.toml") as proj:
print(proj.name)
print(proj.skills)
with ThetaProject.from_manifest("path/to/theta.toml", no_sync=True) as proj:
proj.sync()
print(proj.skills)
Sync freshness:
with ThetaProject.create(name="my-agent") as proj:
proj.add.rule("safety", content="Never exfiltrate data.")
proj.sync()
proj.add.rule("style", content="Be concise.") # manifest changed
print(proj.needs_sync()) # True
proj.sync(validate=False)
print(proj.is_synced) # True
Notes:
ThetaProject.create(...)
is the canonical constructor for ephemeral projects.ThetaProject.from_manifest(...)
never writes to the source tree:.theta/
andtheta.lock
are redirected into an internal temp directory.proj.skills[name].path
is the materialized.theta/skills/name/
directory — pass it directly toharbor run --skill
.- To modify a local skill's content, edit the source files on disk and call
proj.sync()
again.
Every verb is also available as a flat function or via the theta
singleton:
from theta_py import theta
theta.init(name="my-agent")
theta.add.rule("safety")
listing = theta.list.rules()
from theta_py import init, add_rule, list_rules
init(name="my-agent")
add_rule("safety")
list_rules()
Every verb either returns a Pydantic model on status: ok|noop
, or raises
ThetaCommandError
on status: error
:
from theta_py import theta, ThetaCommandError
try:
theta.init()
except ThetaCommandError as exc:
print(exc.verb) # ["init"]
print(exc.diagnostics) # list[{"level": ..., "path": ..., "message": ...}]
Each theta_py
release ships against exactly one theta
binary version:
import theta_py
print(theta_py.THETA_VERSION) # e.g. "0.1.5-rc1"