Weave — the Powerloom CLI. Declarative manifests (apply/plan/destroy) + resource inspection, validated against the authoritative JSON Schema published in this repo.
Project description
loomcli
Schema language + CLI for Powerloom — the Terraform-like declarative framework for Claude Managed Agents.
This repo is the source of truth for the Powerloom manifest schema (apiVersion: powerloom.app/v1) and the weave command-line tool that authors + applies manifests against a Powerloom control plane.
- PyPI:
loomcli - Binary:
weave(console script installed by pip) - Repo:
github.com/shanerlevy-debug/loomcli - Platform it orchestrates:
github.com/shanerlevy-debug/Powerloom
Install
pip install loomcli
weave --version
For other install paths (single binary, from source), see the Powerloom monorepo's docs/install-weave.md.
Why loom + weave (naming)
The platform is Powerloom. The CLI tool is Loom (the PyPI wheel + Python module + git repo name), and its console script is weave (what Loom does). Mirrors the kubectl / Kubernetes pattern: platform name distinct from tool name, tool name distinct from command you type.
Layout
.
├── loomcli/ # Python package (Typer CLI)
│ ├── cli.py # app root
│ ├── auth.py # login + token persistence
│ ├── client.py # HTTP client against Powerloom REST
│ ├── commands/ # subcommands: apply, plan, get, workflow, agent-session, ...
│ └── manifest/ # parser, planner, applier, jsonschema validator
├── schema/
│ └── v1/ # authoritative JSON Schema
│ ├── powerloom-dialect.schema.json # meta-schema defining x-powerloom-* keywords
│ ├── dialect-docs.md # narrative docs for each dialect extension
│ ├── powerloom.v1.bundle.json # assembled multi-kind bundle
│ └── kinds/ # one JSON Schema per manifest kind
├── examples/
│ └── minimal/ # one minimal valid manifest per kind
├── tests/
│ ├── test_*.py # CLI tests (47+)
│ └── schema/ # schema tests — parse + validate + cross-refs (5)
├── pyproject.toml
├── loomcli.spec # PyInstaller spec (single-binary build)
├── build-binary.sh
├── LICENSE # Elastic License v2 (ELv2)
├── CHANGELOG.md
└── .github/workflows/
└── publish.yml # PyPI OIDC trusted publish (tag triggered)
Quickstart — author + apply a manifest
weave auth login --dev-as admin@dev.local # local dev
cat > agent.yaml <<'EOF'
apiVersion: powerloom/v1
kind: OU
metadata:
name: engineering
parent_ou_path: /dev-org
spec:
display_name: Engineering
---
apiVersion: powerloom/v1
kind: Agent
metadata:
ou_path: /dev-org/engineering
name: code-reviewer
spec:
display_name: Code Reviewer
model: claude-sonnet-4-6
system_prompt: "Review Python code for bugs and style."
owner_principal_ref: user:admin@dev.local
skills: [python-lint]
EOF
weave plan agent.yaml # show what apply would do (Terraform-style diff)
weave apply agent.yaml # apply; prompts for confirmation
weave get agents --ou /dev-org/engineering
Supported kind: values
| Kind | Metadata | Notes |
|---|---|---|
OU |
name, parent_ou_path |
Root OUs omit parent_ou_path. |
Group |
name, ou_path |
|
GroupMembership |
group_path, member_ref |
member_ref: user:<email> or group:<path> |
RoleBinding |
principal_ref, role, scope_ou_path, decision_type |
decision_type is allow or deny |
Skill |
name, ou_path |
current_version_id on spec must be pre-uploaded via REST. |
MCPServerRegistration |
name, ou_path |
BYO — pre-existing URL. |
MCPDeployment |
name, ou_path |
14+ templates (files / postgres / slack / github / notion / jira / ...). |
Agent |
name, ou_path |
skills and mcp_servers on spec expand to AgentSkill/AgentMCPServer resources. |
AgentSkill |
agent_path, skill_path |
Usually implicit via Agent.skills. |
AgentMCPServer |
agent_path, mcp_registration_path |
Usually implicit via Agent.mcp_servers. |
Credential |
agent_path, mcp_registration_path |
Bearer minted server-side; no secret material in YAML. |
SkillAccessGrant |
skill_path, principal_ref |
Additive allowlist beyond OU-scoped RBAC. |
Workflow |
name, ou_path |
Phase-14 feature. |
Commands
weave plan manifest.yaml # show what apply would do
weave apply manifest.yaml # apply; prompts for confirmation
weave apply -y ./manifests/ # directory + auto-approve
weave destroy manifest.yaml # reverse-order teardown
weave get agents --ou /dev-org/engineering
weave get mcp-deployments -o json
weave describe agent /dev-org/engineering/code-reviewer
weave import agent /dev-org/engineering/code-reviewer > agent.yaml
weave auth whoami
weave ask /dev-org/alfred "What should I work on next?"
weave chat /dev-org/alfred
weave agent status /dev-org/alfred
weave agent config /dev-org/alfred
weave agent set-model /dev-org/alfred --model gpt-5.5
weave session tail <session-id>
weave profile set --default-agent /dev-org/alfred --default-runtime openai --default-model gpt-5.5
weave commands --json
weave approval wait <approval-id>
weave doctor
weave plugin doctor
weave plugin instructions codex
weave workflow apply workflow.yaml
weave workflow run my-workflow --inputs scope=example
weave workflow status <run-id>
weave agent-session register --scope "<slug>" --summary "<one-line>"
weave agent-session ls --status active
weave agent-session status <coordination-session-id>
weave thread my-work --watch
Global flags:
--api-url URL Override POWERLOOM_API_BASE_URL
--config-dir PATH Override POWERLOOM_HOME
--version Print CLI version and exit
Agentic CLI
weave ask and weave chat make the terminal experience closer to Claude Code, Gemini CLI, and Codex CLI while keeping Powerloom provider-agnostic:
weave ask /dev-org/alfred "Summarize my open work."
weave chat /dev-org/alfred
The CLI invokes a Powerloom Agent through the control plane. It does not read model-provider API keys locally; the backend uses the Agent's configured runtime/model and the user/org runtime credential stored in Powerloom.
Agent identifiers can be UUIDs, full /ou/path/agent-name addresses, or bare names with --ou.
Agent/session observability
These commands inspect runtime state. They do not change manifest-backed Agent configuration:
weave agent status /dev-org/alfred
weave agent sessions /dev-org/alfred
weave agent watch /dev-org/alfred --interval 3
weave session events <session-id>
weave session tail <session-id>
weave agent-session status <coordination-session-id>
weave agent-session watch <coordination-session-id>
weave thread my-work --watch
Use weave agent ... and weave session ... for runtime execution state. Use weave agent-session ... and weave thread my-work for coordination state: what a human or agent has claimed, which workflow tasks are assigned, and what tracker threads are active.
Self-hosted agent daemon (weave agent run)
For agents registered with runtime_type='self_hosted' (the reconciler is the v1 reference), operators run the daemon on their own host — your local server, a customer's, anywhere there's a Python process. The daemon polls the platform for work and dispatches each item to the matching skill handler:
weave agent run reconciler # foreground, 10s tick (default)
weave agent run reconciler --once # single tick + exit (cron-friendly)
weave agent run reconciler --dry-run # decide but don't take destructive actions
weave agent run reconciler --interval 30 # poll cadence in seconds
weave agent run reconciler --confidence 0.9 # threshold for destructive actions (default 0.8)
weave agent run reconciler --limit 25 # items per tick (default 10)
Foreground only — Ctrl+C stops cleanly. For background runs, use the OS supervisor of choice:
# systemd: ExecStart=weave agent run reconciler
# nohup: nohup weave agent run reconciler > daemon.log 2>&1 &
# Windows NSSM: nssm install PowerloomReconciler "C:\Python311\python.exe" "-m loomcli agent run reconciler"
Architecture invariants
- Daemon never holds destructive credentials. Every action flows through the platform API. The daemon is a polling-loop dispatcher, not a business-logic engine.
- Decisions billed against your org's BYOK runtime credential (
runtime_type='cma') — set up once via/settings/api-keysin the Powerloom UI. No provider keys on the operator host. - Daemon is stateless between ticks. The platform DB is the source of truth for the agent's state tables; the daemon's tick loop reads, decides, acts, repeats.
- Skill registry is import-time-pluggable. The
pr_reconciliationskill ships with v0.7.9. Future self-hosted agents (legal review, ad optimization, anything) plug in by adding a new skill handler — no CLI changes, no platform changes.
Operator setup checklist
Before the first run on a fresh host:
- Sign in:
weave login(againsthttps://api.powerloom.orgor your control plane's address). - Confirm BYOK: in the Powerloom UI, ensure your org has a
runtime_type='cma'runtime credential populated with a real provider key. The reconciler errors at SDK construction without one. - Smoke test:
weave agent run reconciler --dry-run --once— should print one tick of decisions without taking action. If it prints0 item(s), no actionable PRs are queued; that's normal. - Confirm the agent advertises a handled task_kind:
weave agent status reconcilershould listpr_reconciliationundertask_kinds. If your daemon prints a "no handler registered" warning, you're either on a stale loomcli (bump to ≥ v0.7.9) or the agent advertises a task_kind we don't ship a skill for yet. - Run for real:
weave agent run reconciler— leave it foregrounded, watch the tick log. Promote to systemd / NSSM once you trust the cadence.
Agent config and CLI profiles
Provider/model selection stays schema-safe:
weave agent config /dev-org/alfred
weave agent set-model /dev-org/alfred --model gpt-5.5
weave profile set --default-runtime openai --default-model gpt-5.5
weave profile show
weave agent set-model updates the Agent row through the control plane. Runtime/provider changes still belong in manifests (weave apply) until Powerloom exposes a safe runtime patch endpoint. Profiles store local defaults in config.toml; they do not change remote resources by themselves.
Command discovery and approvals
weave commands --json
weave approval wait <approval-id>
weave commands exports command metadata for autocomplete, mobile clients, and plugin docs. weave approval wait polls a pending approval until it is approved, rejected, cancelled, expired, or times out.
Setup diagnostics and client plugins
weave doctor
weave plugin doctor
weave plugin install claude-code
weave plugin install codex
weave plugin install gemini
weave agent-session bootstrap --project powerloom --client codex_cli
weave doctor checks local auth, the configured API URL, advertised server capabilities, supported actor kinds, and common client binaries on PATH. weave plugin doctor checks local plugin package paths for Claude Code, Codex, Gemini, and Antigravity. Install commands default to dry-run output; pass --execute only after reviewing the command. Use --client claude_code, --client codex_cli, or --client gemini_cli with agent-session bootstrap to use the same checkout-and-register flow for each CLI.
Plugin assets are exported on first use. On Windows the default plugin cache is %USERPROFILE%\.powerloom\plugins\<version> so client CLIs can read the files even when Python is installed from the Microsoft Store. Set POWERLOOM_PLUGIN_HOME to override only the plugin cache, or POWERLOOM_HOME to override the full Powerloom config root.
Schema as source of truth
Manifests are validated at CLI runtime against schema/v1/. The same schema is consumed by:
- Powerloom server-side Pydantic — reads the schema and generates typed request/response models (planned upstream adoption; today hand-maintained with a drift detector).
- IDE
yaml-language-server— `# yaml-language-server: $schema=...` headers on example manifests underexamples/enable inline validation in VSCode / JetBrains / vim-lsp. - LLM-authored manifests — any Claude session handed the schema + dialect docs can produce correct manifests first-try.
Using a single source for all four paths makes drift impossible by construction.
Industry-standard pattern: kubectl, Helm, Argo, and Flux all validate user-submitted manifests against a published JSON Schema (or CRD) at runtime. Pydantic / struct-tag validation is an implementation detail downstream of the wire-format schema.
Dialect extensions
Beyond vanilla JSON Schema Draft 2020-12, Powerloom defines x-powerloom-* keywords that carry control-plane semantics:
x-powerloom-server-populated— field is populated by the server, not the author.x-powerloom-immutable— field set at create, immutable thereafter.x-powerloom-reconciler— reconciler behavior hints.x-powerloom-ref— cross-kind reference (e.g. Agent → Skill).x-powerloom-tier-gate— minimum tier required for the feature.
Full reference: schema/v1/dialect-docs.md.
Versioning
- Schema: semver git tags
schema-v1.x.y. Breaking changes bump the major; additive changes bump the minor; docs-only or wording-only changes bump the patch. - CLI (PyPI): semver git tags
vX.Y.Zon this repo. Trigger PyPI publish. Track CLI version withweave --version. - Per-kind: optional
kind: Agent/v2qualifier lets individual kinds evolve independently inside a major.
The Powerloom monorepo pins this repo's schema to a specific version via pip install loomcli==<version> in its dev dependencies (no git submodule).
Development
git clone https://github.com/shanerlevy-debug/loomcli.git
cd loomcli
pip install -e ".[dev]"
pytest # 47 CLI + 5 schema tests
weave --version
Build the single binary
./build-binary.sh # -> dist/weave (or weave.exe on Windows)
./dist/weave --version
PyInstaller produces a platform-native single-file binary with the JSON Schema bundled inside — no Python required on the target machine. Cross-platform matrix (Linux / macOS / Windows / arm64) is tracked in the Powerloom monorepo's docs/loomcli-overhaul.md M1.b.
Release workflow
Publish to PyPI on tag push:
# 1. Bump version in pyproject.toml (X.Y.Z semver).
# 2. Commit + push.
# 3. Tag and push:
git tag v0.4.0
git push origin v0.4.0
The .github/workflows/publish.yml workflow runs preflight (tag matches pyproject version, schema bundle present), builds wheel + sdist, smoke-tests the wheel (install + weave --version + --help), verifies the schema is inside the wheel, then publishes to PyPI via OIDC Trusted Publishing (no API token).
Optional TestPyPI dry-run:
gh workflow run publish.yml -f target=testpypi
License
Elastic License v2 (ELv2). See LICENSE.
Intentional gaps
- No
weave edit(in-place kubectl-style editor). Post-Phase-13. - No
weave logs <session-id> --follow(WebSocket tail). Post-Phase-13. - No bulk export (
weave export --all). Per-resourceimportonly. - Local skill-archive upload via manifest (
local_archive: ./skill.tar.gz) not supported — upload via REST first, reference the resultingcurrent_version_idby UUID. - OIDC device-code login is stubbed; dev-mode impersonation is the working login path until Phase 9 ships in Powerloom.
- Cross-platform binary matrix not yet wired — build on your host OS for now.
- Server-side Pydantic codegen from this schema not yet adopted in the Powerloom monorepo (drift-detector covers the hand-maintained case).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file loomcli-0.7.9.tar.gz.
File metadata
- Download URL: loomcli-0.7.9.tar.gz
- Upload date:
- Size: 408.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
38d9153edc9228b716c19ce94c6968b2c4a4712b213d1238bc03f6c39a394278
|
|
| MD5 |
9f399d8350600d0785324a920fa0e7dc
|
|
| BLAKE2b-256 |
700311a9152e8cd2a594a14ad848dd40630e5fe02513a9d65826e055d9723a68
|
Provenance
The following attestation bundles were made for loomcli-0.7.9.tar.gz:
Publisher:
publish.yml on shanerlevy-debug/loomcli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
loomcli-0.7.9.tar.gz -
Subject digest:
38d9153edc9228b716c19ce94c6968b2c4a4712b213d1238bc03f6c39a394278 - Sigstore transparency entry: 1398950298
- Sigstore integration time:
-
Permalink:
shanerlevy-debug/loomcli@7438ee294f006edc38d4f25266463cc829afa205 -
Branch / Tag:
refs/tags/v0.7.9 - Owner: https://github.com/shanerlevy-debug
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7438ee294f006edc38d4f25266463cc829afa205 -
Trigger Event:
push
-
Statement type:
File details
Details for the file loomcli-0.7.9-py3-none-any.whl.
File metadata
- Download URL: loomcli-0.7.9-py3-none-any.whl
- Upload date:
- Size: 331.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2a801e55309206d31410517edcf69e6fc3020027a40fafab7e71639d45ee9a65
|
|
| MD5 |
605d6b22dd6cc2d9dd688102af094b78
|
|
| BLAKE2b-256 |
af25e0c6bf2dbdea02813157989208f93e506f40dfacb6a4cffc163af1796393
|
Provenance
The following attestation bundles were made for loomcli-0.7.9-py3-none-any.whl:
Publisher:
publish.yml on shanerlevy-debug/loomcli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
loomcli-0.7.9-py3-none-any.whl -
Subject digest:
2a801e55309206d31410517edcf69e6fc3020027a40fafab7e71639d45ee9a65 - Sigstore transparency entry: 1398950316
- Sigstore integration time:
-
Permalink:
shanerlevy-debug/loomcli@7438ee294f006edc38d4f25266463cc829afa205 -
Branch / Tag:
refs/tags/v0.7.9 - Owner: https://github.com/shanerlevy-debug
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7438ee294f006edc38d4f25266463cc829afa205 -
Trigger Event:
push
-
Statement type: