Skip to content

Commit 43dc3df

Browse files
Initial release of 1Claw Python SDK (v0.1.0)
Full-featured Python SDK for the 1Claw secrets management platform, mirroring the TypeScript SDK architecture. Built from the OpenAPI spec. - Core HTTP client with auto JWT refresh for agent keys (ocv_) - 18 resource modules: auth, vaults, secrets, agents, policies, chains, sharing, billing, audit, org, api_keys, signing_keys, treasury, treasury_wallets, platform, approvals, webhooks, risk - Comprehensive error hierarchy (AuthError, NotFoundError, etc.) - Envelope response pattern (OneclawResponse with data/error/meta) - Single runtime dependency: httpx - 17 unit tests with respx mocking - Clean ruff linting and mypy type stubs (py.typed) - PyPI-ready with hatchling build system - CI/CD workflow for automated testing and publishing Co-authored-by: Cursor <cursoragent@cursor.com>
0 parents  commit 43dc3df

32 files changed

Lines changed: 3586 additions & 0 deletions

.github/workflows/ci.yml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
- uses: actions/setup-python@v5
19+
with:
20+
python-version: ${{ matrix.python-version }}
21+
22+
- name: Install dependencies
23+
run: |
24+
pip install -e ".[dev]"
25+
26+
- name: Lint
27+
run: ruff check src/ tests/
28+
29+
- name: Type check
30+
run: mypy src/oneclaw/ --ignore-missing-imports
31+
32+
- name: Test
33+
run: pytest -v
34+
35+
publish:
36+
needs: test
37+
runs-on: ubuntu-latest
38+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
39+
permissions:
40+
id-token: write
41+
steps:
42+
- uses: actions/checkout@v4
43+
- uses: actions/setup-python@v5
44+
with:
45+
python-version: "3.12"
46+
47+
- name: Build
48+
run: |
49+
pip install build
50+
python -m build
51+
52+
- name: Publish to PyPI
53+
uses: pypa/gh-action-pypi-publish@release/v1

.gitignore

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
__pycache__/
2+
*.py[cod]
3+
*$py.class
4+
*.egg-info/
5+
dist/
6+
build/
7+
.eggs/
8+
*.egg
9+
.mypy_cache/
10+
.ruff_cache/
11+
.pytest_cache/
12+
.venv/
13+
venv/
14+
env/
15+
*.so
16+
.coverage
17+
htmlcov/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 1Claw
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
# 1Claw Python SDK
2+
3+
Official Python SDK for the [1Claw](https://1claw.xyz) secrets management platform.
4+
5+
[![PyPI version](https://img.shields.io/pypi/v/oneclaw.svg)](https://pypi.org/project/oneclaw/)
6+
[![Python versions](https://img.shields.io/pypi/pyversions/oneclaw.svg)](https://pypi.org/project/oneclaw/)
7+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8+
9+
## Installation
10+
11+
```bash
12+
pip install oneclaw
13+
```
14+
15+
## Quick Start
16+
17+
### Agent Authentication (API Key)
18+
19+
```python
20+
from oneclaw import create_client
21+
22+
# Agent keys (ocv_) auto-exchange for JWTs and refresh before expiry
23+
client = create_client(api_key="ocv_your_agent_key")
24+
25+
# Agent ID is auto-discovered from the token exchange
26+
print(client.resolved_agent_id)
27+
```
28+
29+
### User Authentication
30+
31+
```python
32+
from oneclaw import create_client
33+
34+
# User API key (1ck_) — auto-exchanges for JWT
35+
client = create_client(api_key="1ck_your_user_key")
36+
37+
# Or login with email/password
38+
client = create_client()
39+
client.auth.login("user@example.com", "password")
40+
```
41+
42+
### Pre-authenticated with JWT
43+
44+
```python
45+
client = create_client(token="eyJ...")
46+
```
47+
48+
## Usage
49+
50+
### Vaults
51+
52+
```python
53+
# Create a vault
54+
resp = client.vaults.create("my-vault", description="Production secrets")
55+
vault_id = resp.data["id"]
56+
57+
# List vaults
58+
vaults = client.vaults.list()
59+
for v in vaults.data["vaults"]:
60+
print(v["name"])
61+
```
62+
63+
### Secrets
64+
65+
```python
66+
# Store a secret
67+
client.secrets.set(vault_id, "api-key", "sk-secret-value")
68+
69+
# Retrieve a secret
70+
secret = client.secrets.get(vault_id, "api-key")
71+
print(secret.data["value"])
72+
73+
# Server-side rotation (vault generates a random value)
74+
client.secrets.rotate_generate(vault_id, "api-key", length=64, charset="base64")
75+
76+
# List versions
77+
versions = client.secrets.list_versions(vault_id, "api-key")
78+
```
79+
80+
### Agents
81+
82+
```python
83+
# Register an agent
84+
resp = client.agents.create("my-agent", description="CI/CD bot")
85+
agent = resp.data["agent"]
86+
api_key = resp.data["api_key"] # Save this — shown only once
87+
88+
# Self-enroll (no auth required)
89+
client.agents.enroll("my-agent", "admin@example.com")
90+
```
91+
92+
### Access Policies
93+
94+
```python
95+
# Grant an agent read access to secrets matching a pattern
96+
client.policies.create(
97+
vault_id,
98+
principal_type="agent",
99+
principal_id=agent_id,
100+
secret_path_pattern="production/*",
101+
permissions=["read"],
102+
)
103+
```
104+
105+
### Intents API (Transaction Signing)
106+
107+
```python
108+
# Submit a transaction
109+
resp = client.agents.submit_transaction(
110+
agent_id,
111+
chain="ethereum",
112+
to="0x...",
113+
value="1000000000000000", # wei
114+
max_fee_per_gas="30000000000",
115+
max_priority_fee_per_gas="1000000000",
116+
)
117+
print(resp.data["tx_hash"])
118+
119+
# Unified signing (personal_sign, typed_data, transaction)
120+
resp = client.agents.sign_intent(
121+
agent_id,
122+
intent_type="personal_sign",
123+
chain="ethereum",
124+
message="0x48656c6c6f",
125+
)
126+
print(resp.data["signature"])
127+
```
128+
129+
### Signing Keys
130+
131+
```python
132+
# Provision a signing key
133+
client.signing_keys.create(agent_id, "ethereum")
134+
135+
# List keys
136+
keys = client.signing_keys.list(agent_id)
137+
138+
# Check balance
139+
balance = client.signing_keys.balance(agent_id, "ethereum")
140+
```
141+
142+
### Treasury
143+
144+
```python
145+
# Create a treasury
146+
client.treasury.create("Team Treasury", safe_address="0x...", chain="ethereum")
147+
148+
# Create a multisig proposal
149+
client.treasury.propose(treasury_id, chain="ethereum", to="0x...", value="1000000000")
150+
151+
# Sign a proposal
152+
client.treasury.sign_proposal(treasury_id, proposal_id, signature="0x...", decision="approve")
153+
```
154+
155+
### Treasury Wallets
156+
157+
```python
158+
# Generate wallets for all supported chains
159+
client.treasury_wallets.generate()
160+
161+
# Check balance
162+
balance = client.treasury_wallets.balance("ethereum")
163+
164+
# Send tokens (requires password re-auth)
165+
client.treasury_wallets.send(
166+
"ethereum",
167+
to="0x...",
168+
value="1000000000000000",
169+
password="your-account-password",
170+
)
171+
```
172+
173+
### Platform API
174+
175+
```python
176+
# Register a platform app
177+
resp = client.platform.create_app("My App", "my-app")
178+
plt_key = resp.data["api_key"] # Save this
179+
180+
# Provision a user
181+
conn = client.platform.upsert_user(email="user@example.com")
182+
183+
# Bootstrap resources from a template
184+
bootstrap = client.platform.bootstrap_user(conn.data["connection_id"])
185+
```
186+
187+
### Webhooks
188+
189+
```python
190+
client.webhooks.create(
191+
url="https://example.com/webhook",
192+
events=["agent.transaction.broadcast", "proposal.executed"],
193+
secret="whsec_...",
194+
)
195+
```
196+
197+
### Risk Engine
198+
199+
```python
200+
# List risk events
201+
events = client.risk.list_events(severity="high")
202+
203+
# Register a honeytoken
204+
client.risk.create_honeytoken(vault_id, "canary/secret-key")
205+
```
206+
207+
## Error Handling
208+
209+
```python
210+
from oneclaw import create_client, OneclawError, AuthError, NotFoundError
211+
212+
client = create_client(api_key="ocv_...")
213+
214+
# Envelope-style (no exceptions)
215+
resp = client.vaults.get("nonexistent-id")
216+
if resp.error:
217+
print(f"Error: {resp.error.message}")
218+
219+
# Exception-style (use the underlying HTTP client)
220+
try:
221+
data = client._http.request_or_throw("GET", "/v1/vaults/bad-id")
222+
except NotFoundError:
223+
print("Vault not found")
224+
except AuthError:
225+
print("Authentication failed")
226+
except OneclawError as e:
227+
print(f"API error: {e} (status={e.status})")
228+
```
229+
230+
## Context Manager
231+
232+
```python
233+
with create_client(api_key="ocv_...") as client:
234+
vaults = client.vaults.list()
235+
# Connection pool is automatically closed
236+
```
237+
238+
## Configuration
239+
240+
| Parameter | Default | Description |
241+
|-----------|---------|-------------|
242+
| `base_url` | `https://api.1claw.xyz` | API base URL |
243+
| `token` | `None` | Pre-existing JWT |
244+
| `api_key` | `None` | `ocv_` (agent) or `1ck_` (user) key |
245+
| `agent_id` | `None` | Agent UUID (optional, auto-discovered) |
246+
| `timeout` | `30.0` | HTTP timeout in seconds |
247+
248+
## Requirements
249+
250+
- Python 3.9+
251+
- [httpx](https://www.python-httpx.org/) (only runtime dependency)
252+
253+
## License
254+
255+
MIT

0 commit comments

Comments
 (0)