Skip to content

Commit 18794a7

Browse files
committed
Refocus README on client usage and add Subfork banner
1 parent 6f27355 commit 18794a7

3 files changed

Lines changed: 102 additions & 94 deletions

File tree

‎CONTRIBUTING.md‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Contributing
2+
3+
Install the development dependencies using Python 3.8+ and a modern pip:
4+
5+
```bash
6+
python -m pip install --upgrade pip
7+
python -m pip install -e '.[dev]'
8+
```
9+
10+
## Code quality
11+
12+
13+
Install `.[dev]` to get the pinned development tools. Black 24.8.0, isort 5.13.2,
14+
and Flake8 7.1.1 follow the conventions used in the sibling envstack and pyseq
15+
projects: 100-column formatting, isort's Black profile, and a Python 3.8 target.
16+
The tool versions also support running locally under Python 3.8.
17+
18+
```bash
19+
make format # Sort imports and apply Black to src/ and tests/
20+
make lint # Check formatting, imports, Flake8 and Google-style docstrings
21+
make typecheck # Check annotated library code with mypy
22+
make test # Run the HTTP contract tests
23+
make check # Run lint, type checking and tests
24+
make build # Build distributions and check their metadata
25+
```
26+
27+
Activate your environment first, or specify it explicitly, for example:
28+
`make check PYTHON=.venv/bin/python`. The CI lint job uses the same commands.
29+
EditorConfig defines whitespace and newline conventions for supporting editors.
30+
31+
Add annotations and docstrings to new functions, methods and classes, including
32+
constructors and test helpers. Public docstrings should explain side effects,
33+
permissions, return values and failure behavior where useful. JSON dictionaries
34+
retain `Any` values because node parameters and server response fields are dynamic;
35+
this release does not pretend to provide complete generated response models.
36+
Mypy checks library signatures and bodies; Flake8 and formatting cover both the
37+
library and tests. Runtime tests continue to cover Python 3.8 in CI.

‎README.md‎

Lines changed: 65 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,52 @@
1-
# subfork
1+
<div class="gridline-home-hero">
2+
<a href="https://subfork.com">
3+
<img src="assets/subfork-banner.png" alt="Subfork" width="100%">
4+
</a>
5+
<p>Create, publish, and run graphs from Python.</p>
6+
</div>
27

3-
Python API client for Subfork graph authoring, publication and execution.
4-
**Alpha scaffold; not yet published to PyPI.** Distribution and import name: `subfork`.
5-
BYO workers belong in the separate worker package, not this client.
8+
# Subfork Python
69

7-
## Development install
10+
The Python client for [Subfork](https://subfork.com). Discover nodes, build reusable
11+
graphs, publish versions, and run them from your scripts, applications, or agents.
812

9-
Requires Python 3.8+ and a modern pip (21.3+ for editable installs).
10-
Use a supported interpreter explicitly; the system `python3` may be older.
13+
## Install
1114

12-
```bash
13-
python3 -m venv .venv
14-
source .venv/bin/activate
15-
python -m pip install --upgrade pip
16-
python -m pip install -e '.[dev]'
17-
pytest
18-
python -m build
19-
python -m twine check dist/*
20-
```
21-
22-
If pip reports that editable mode requires `setup.py`, check `python --version`
23-
and `python -m pip --version`. Upgrade pip inside the active environment:
24-
`python -m pip install --upgrade pip`. Python 3.8 is supported; pip will select
25-
the latest pip and dependencies compatible with that interpreter. A `setup.py`
26-
compatibility shim is not needed.
27-
28-
With [uv](https://docs.astral.sh/uv/), a supported Python can also be provisioned
29-
without changing the system Python. Preserve an existing environment by using a
30-
new directory:
15+
Requires Python 3.8+.
3116

3217
```bash
33-
uv venv --python 3.12 .venv312
34-
source .venv312/bin/activate
35-
uv pip install -e '.[dev]'
18+
pip install subfork
3619
```
3720

38-
Licensed under [BSD-3-Clause](LICENSE). CI builds and checks distributions but does
39-
not publish them.
40-
41-
## Usage
21+
## Connect
4222

43-
Create an API key under Account → API keys on a deployment with API-key support.
44-
Set `SUBFORK_API_KEY` in your process environment; never put it in source files,
45-
URLs, graph definitions, notebooks committed to git, or agent transcripts.
23+
Create a key under **Account → API keys** in Subfork and set `SUBFORK_API_KEY` in
24+
your environment. Grant the permissions your application needs: read, write, run,
25+
and/or publish. Keep the key out of source files and graph definitions.
4626

4727
```python
4828
from subfork import Subfork
4929

50-
with Subfork() as client: # Reads SUBFORK_API_KEY; defaults to https://subfork.com
51-
nodes = client.nodes.list(include_all_versions=True)
30+
with Subfork() as client:
31+
nodes = client.nodes.list()
5232
graphs = client.graphs.list()
5333
```
5434

55-
For a local deployment:
35+
The client reads `SUBFORK_API_KEY` and connects to `https://subfork.com` by default.
36+
Responses are dictionaries and lists matching the API's JSON responses.
37+
38+
For another deployment, pass its origin without `/api/v1`:
5639

5740
```python
5841
with Subfork(base_url="http://subfork.localhost") as client:
5942
nodes = client.nodes.list()
6043
```
6144

62-
`base_url` is an origin, without `/api/v1`. HTTPS is required except for loopback
63-
and `.localhost` hosts. Credentials are sent in the Authorization bearer header.
64-
Redirects are not followed. Use a context manager or call `client.close()`.
45+
## Create and run a graph
6546

66-
## Author, publish, execute
67-
68-
The following deliberately creates and publishes a public graph and consumes
69-
execution quota. Grant read/write/run/publish scopes only when needed.
70-
Responses are dictionaries preserving the server's JSON shape.
47+
This example creates a text-producing graph, publishes `v1`, and runs that version.
48+
It requires read, write, publish, and run permissions. Graphs are public, and runs
49+
use your account's execution quota.
7150

7251
```python
7352
from subfork import Subfork
@@ -76,71 +55,63 @@ name = "Python greeting"
7655
definition = {
7756
"name": name,
7857
"nodes": [{
79-
"node_instance_id": "hello", "node_id": "n_text_value",
80-
"node_version": "1.0.0", "title": "Hello",
58+
"node_instance_id": "hello",
59+
"node_id": "n_text_value",
60+
"node_version": "1.0.0",
61+
"title": "Hello",
8162
"params": {"text": "Hello from Python"},
8263
}],
8364
"edges": [],
84-
"graph_outputs": {"text": {"node_instance_id": "hello", "output_name": "text"}},
65+
"graph_outputs": {
66+
"text": {"node_instance_id": "hello", "output_name": "text"},
67+
},
8568
}
69+
8670
with Subfork() as client:
8771
client.graphs.validate(definition)
8872
graph = client.graphs.create(name=name, definition=definition)
8973
client.graphs.publish(graph["id"], version="v1")
74+
9075
execution = client.graphs.execute(graph["id"], version="v1")
9176
result = client.executions.wait(execution["id"], timeout=120)
9277
print(result["status"], result.get("outputs"))
9378
```
9479

95-
Discover published blocks with `graphs.published()` and retrieve their exact
96-
interfaces with `graphs.published_version(graph_id, version)`. Compose their
97-
returned node IDs with `composite_graph` parameters and explicit pinned versions.
98-
`graphs.interface(graph_id)` previews the server-inferred interface.
99-
`graphs.update()` replaces the submitted draft fields, including description;
100-
pass the description to preserve it. Existing server ownership and quotas apply.
80+
To test a draft before publishing, call `graphs.execute(graph_id)` without a
81+
version. To update a draft, use `graphs.update()` with its name, definition, and
82+
description; omitting the description clears it.
10183

102-
## Errors and limits
84+
## Reuse building blocks
10385

104-
Catch `AuthenticationError`, `PermissionDeniedError`, `ValidationError`,
105-
`RateLimitError`, or the base `APIError`; HTTP errors expose `status_code` and
106-
`retry_after`. Messages intentionally do not echo raw response bodies or secrets.
107-
`TransportError` means the outcome of a write may be unknown. There are no automatic
108-
retries: inspect remote state before retrying create, publish or execute operations.
86+
Explore published graphs and inspect their versioned interfaces:
10987

110-
`executions.wait()` polls until a terminal status and returns failed executions
111-
as results too. `ExecutionTimeout` does **not** cancel the remote execution;
112-
use `executions.cancel(id)` explicitly. Polling uses a monotonic deadline and caps
113-
individual HTTP timeout settings by remaining time. HTTPX timeouts apply per I/O
114-
phase, not a strict wall-clock deadline for the entire network exchange.
88+
```python
89+
with Subfork() as client:
90+
blocks = client.graphs.published()
91+
block = client.graphs.published_version(graph_id, "v1")
92+
```
11593

116-
The first scaffold is synchronous. Async support, rich response models, artifact
117-
streaming, idempotent write retries and worker support are not included. Mock HTTP
118-
tests do not certify any particular server deployment.
94+
Replace `graph_id` with the ID of a graph you want to use. Published graph versions
95+
can be composed into larger graphs using the returned composite node manifest.
96+
Pin child versions so later publications do not change your graph's behavior.
11997

120-
## Code quality
98+
## Handle failures
12199

122-
Install `.[dev]` to get the pinned development tools. Black 24.8.0, isort 5.13.2,
123-
and Flake8 7.1.1 follow the conventions used in the sibling envstack and pyseq
124-
projects: 100-column formatting, isort's Black profile, and a Python 3.8 target.
125-
The tool versions also support running locally under Python 3.8.
100+
HTTP failures raise `APIError` subclasses, including `AuthenticationError`,
101+
`PermissionDeniedError`, `ValidationError`, and `RateLimitError`. These expose
102+
`status_code` and an optional `retry_after` header.
126103

127-
```bash
128-
make format # Sort imports and apply Black to src/ and tests/
129-
make lint # Check formatting, imports, Flake8 and Google-style docstrings
130-
make typecheck # Check annotated library code with mypy
131-
make test # Run the HTTP contract tests
132-
make check # Run lint, type checking and tests
133-
make build # Build distributions and check their metadata
134-
```
104+
`executions.wait()` returns failed and canceled runs as well as successful ones,
105+
so check the returned status. An `ExecutionTimeout` stops polling but does not
106+
cancel the remote run; use `executions.cancel(execution_id)` to request cancellation.
107+
108+
The client does not automatically retry requests. After a `TransportError`, check
109+
remote state before repeating a create, publish, or execute request.
110+
111+
## Contributing
112+
113+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development and code-quality checks.
114+
115+
## License
135116

136-
Activate your environment first, or specify it explicitly, for example:
137-
`make check PYTHON=.venv/bin/python`. The CI lint job uses the same commands.
138-
EditorConfig defines whitespace and newline conventions for supporting editors.
139-
140-
Add annotations and docstrings to new functions, methods and classes, including
141-
constructors and test helpers. Public docstrings should explain side effects,
142-
permissions, return values and failure behavior where useful. JSON dictionaries
143-
retain `Any` values because node parameters and server response fields are dynamic;
144-
this release does not pretend to provide complete generated response models.
145-
Mypy checks library signatures and bodies; Flake8 and formatting cover both the
146-
library and tests. Runtime tests continue to cover Python 3.8 in CI.
117+
[BSD-3-Clause](LICENSE).

‎assets/subfork-banner.png‎

211 KB
Loading

0 commit comments

Comments
 (0)