workgraph 0.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Maxime Schmitt
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.
@@ -0,0 +1,139 @@
1
+ Metadata-Version: 2.4
2
+ Name: workgraph
3
+ Version: 0.3.3
4
+ Summary: Graph workflow orchestrator.
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Requires-Dist: termaid[rich]>=0.8.0
8
+ Requires-Dist: tomlkit>=0.15.1
9
+ Requires-Python: >=3.12
10
+ Project-URL: Changelog, https://github.com/sylmarien/workgraph/blob/main/CHANGELOG.md
11
+ Project-URL: Repository, https://github.com/sylmarien/workgraph
12
+ Description-Content-Type: text/markdown
13
+
14
+ # workgraph
15
+
16
+ workgraph orchestrates development workflows declared as graphs. Nodes run
17
+ agents or commands; a node's outcome selects the transition to follow. The
18
+ developer writes the workflow once and starts a run from a harness session
19
+ with `/workgraph`. The run prints one progress line per node. One command
20
+ resumes a stopped run.
21
+
22
+ The CLI bundles workflow and agent definitions; [Workflow
23
+ files](docs/workflow-files.md) lists them. This repository runs the bundled
24
+ `wg` workflow on itself:
25
+
26
+ ```mermaid
27
+ flowchart TD
28
+ design([design])
29
+ design -->|done| approve-design
30
+ approve-design -->|accept| plan
31
+ approve-design -->|reject| design
32
+ plan -->|done| approve-plan
33
+ approve-plan -->|accept| implement
34
+ approve-plan -->|reject| plan
35
+ implement -->|done| test
36
+ test -->|pass| review
37
+ test -->|fail| implement
38
+ review --> code-review
39
+ review --> overengineering-review
40
+ review -->|pass| pr
41
+ review -->|fail| review-loop
42
+ review-loop -->|pass| implement
43
+ review-loop -->|fail| implement
44
+ review-loop -->|LIMIT| summary
45
+ summary -->|done| pr
46
+ pr -->|done| END
47
+ ```
48
+
49
+ ## Install
50
+
51
+ As a Claude Code plugin:
52
+
53
+ ```
54
+ /plugin marketplace add sylmarien/workgraph
55
+ /plugin install workgraph@workgraph
56
+ ```
57
+
58
+ Installing the plugin adds the `/workgraph` skill. The plugin's `install`
59
+ skill installs the CLI with `uv`, and its `update` skill upgrades it. Both
60
+ check that `uv` is on `PATH` and install nothing else.
61
+
62
+ The CLI bundles workflow and agent definitions. A user's own definitions
63
+ shadow them; see [Workflow files](docs/workflow-files.md) for the bundled
64
+ definitions and the resolution order.
65
+
66
+ As a Codex plugin:
67
+
68
+ ```sh
69
+ codex plugin marketplace add sylmarien/workgraph
70
+ codex plugin add workgraph@workgraph
71
+ ```
72
+
73
+ Start a new Codex session and invoke `$workgraph <workflow> "#<issue>"`.
74
+ The plugin shares the install, update, and run skills with the Claude Code
75
+ plugin. The bundled workflows run nodes on the Claude harness, so they
76
+ require `claude` and `uv` on `PATH` in Codex too.
77
+
78
+ Codex reads the repository's existing marketplace at
79
+ `.claude-plugin/marketplace.json` and its manifest at
80
+ `.codex-plugin/plugin.json`. Both plugins ship in the same Git release.
81
+ The patch, minor, and major release workflows update both manifests and
82
+ the CLI to the same version. See the
83
+ [Codex packaging documentation](https://developers.openai.com/plugins/build/plugins).
84
+
85
+ Without the plugin:
86
+
87
+ ```sh
88
+ uv tool install workgraph
89
+ ```
90
+
91
+ `pip install workgraph` installs the same package from PyPI.
92
+ `uv tool upgrade workgraph` upgrades it. Requires Python 3.12+. An agent
93
+ node additionally requires the CLI of its harness on `PATH`: `claude` for
94
+ `harness = "claude"`, `codex` for `harness = "codex"`.
95
+
96
+ ## Example
97
+
98
+ ```sh
99
+ workgraph run wg "#12"
100
+ ```
101
+
102
+ ```
103
+ design: done
104
+ approve-design: parked
105
+ parked at approve-design: Plan from this design? · spent 1m20s · $0.15
106
+ Review material from design:
107
+ https://github.com/sylmarien/workgraph/issues/12#issuecomment-5550441682
108
+ ```
109
+
110
+ ```sh
111
+ workgraph resume --decision accept
112
+ ```
113
+
114
+ ```
115
+ approve-design: accept
116
+ plan: done
117
+ approve-plan: parked
118
+ parked at approve-plan: Implement this plan? · spent 4m05s · $0.42
119
+ Review material from plan:
120
+ <the plan>
121
+ ```
122
+
123
+ `workgraph resume --decision accept` delivers the decision and resumes the
124
+ run.
125
+
126
+ ## Reference
127
+
128
+ - [Commands](docs/commands.md)
129
+ - [Workflow files](docs/workflow-files.md)
130
+ - [Agent definitions](docs/agent-definitions.md)
131
+
132
+ ## Development
133
+
134
+ ```sh
135
+ uv sync
136
+ uv run ruff check && uv run ruff format --check && uv run mypy && uv run pytest
137
+ ```
138
+
139
+ The dogfood workflow runs the same gate: `workgraph run wg "#<issue>"`.
@@ -0,0 +1,126 @@
1
+ # workgraph
2
+
3
+ workgraph orchestrates development workflows declared as graphs. Nodes run
4
+ agents or commands; a node's outcome selects the transition to follow. The
5
+ developer writes the workflow once and starts a run from a harness session
6
+ with `/workgraph`. The run prints one progress line per node. One command
7
+ resumes a stopped run.
8
+
9
+ The CLI bundles workflow and agent definitions; [Workflow
10
+ files](docs/workflow-files.md) lists them. This repository runs the bundled
11
+ `wg` workflow on itself:
12
+
13
+ ```mermaid
14
+ flowchart TD
15
+ design([design])
16
+ design -->|done| approve-design
17
+ approve-design -->|accept| plan
18
+ approve-design -->|reject| design
19
+ plan -->|done| approve-plan
20
+ approve-plan -->|accept| implement
21
+ approve-plan -->|reject| plan
22
+ implement -->|done| test
23
+ test -->|pass| review
24
+ test -->|fail| implement
25
+ review --> code-review
26
+ review --> overengineering-review
27
+ review -->|pass| pr
28
+ review -->|fail| review-loop
29
+ review-loop -->|pass| implement
30
+ review-loop -->|fail| implement
31
+ review-loop -->|LIMIT| summary
32
+ summary -->|done| pr
33
+ pr -->|done| END
34
+ ```
35
+
36
+ ## Install
37
+
38
+ As a Claude Code plugin:
39
+
40
+ ```
41
+ /plugin marketplace add sylmarien/workgraph
42
+ /plugin install workgraph@workgraph
43
+ ```
44
+
45
+ Installing the plugin adds the `/workgraph` skill. The plugin's `install`
46
+ skill installs the CLI with `uv`, and its `update` skill upgrades it. Both
47
+ check that `uv` is on `PATH` and install nothing else.
48
+
49
+ The CLI bundles workflow and agent definitions. A user's own definitions
50
+ shadow them; see [Workflow files](docs/workflow-files.md) for the bundled
51
+ definitions and the resolution order.
52
+
53
+ As a Codex plugin:
54
+
55
+ ```sh
56
+ codex plugin marketplace add sylmarien/workgraph
57
+ codex plugin add workgraph@workgraph
58
+ ```
59
+
60
+ Start a new Codex session and invoke `$workgraph <workflow> "#<issue>"`.
61
+ The plugin shares the install, update, and run skills with the Claude Code
62
+ plugin. The bundled workflows run nodes on the Claude harness, so they
63
+ require `claude` and `uv` on `PATH` in Codex too.
64
+
65
+ Codex reads the repository's existing marketplace at
66
+ `.claude-plugin/marketplace.json` and its manifest at
67
+ `.codex-plugin/plugin.json`. Both plugins ship in the same Git release.
68
+ The patch, minor, and major release workflows update both manifests and
69
+ the CLI to the same version. See the
70
+ [Codex packaging documentation](https://developers.openai.com/plugins/build/plugins).
71
+
72
+ Without the plugin:
73
+
74
+ ```sh
75
+ uv tool install workgraph
76
+ ```
77
+
78
+ `pip install workgraph` installs the same package from PyPI.
79
+ `uv tool upgrade workgraph` upgrades it. Requires Python 3.12+. An agent
80
+ node additionally requires the CLI of its harness on `PATH`: `claude` for
81
+ `harness = "claude"`, `codex` for `harness = "codex"`.
82
+
83
+ ## Example
84
+
85
+ ```sh
86
+ workgraph run wg "#12"
87
+ ```
88
+
89
+ ```
90
+ design: done
91
+ approve-design: parked
92
+ parked at approve-design: Plan from this design? · spent 1m20s · $0.15
93
+ Review material from design:
94
+ https://github.com/sylmarien/workgraph/issues/12#issuecomment-5550441682
95
+ ```
96
+
97
+ ```sh
98
+ workgraph resume --decision accept
99
+ ```
100
+
101
+ ```
102
+ approve-design: accept
103
+ plan: done
104
+ approve-plan: parked
105
+ parked at approve-plan: Implement this plan? · spent 4m05s · $0.42
106
+ Review material from plan:
107
+ <the plan>
108
+ ```
109
+
110
+ `workgraph resume --decision accept` delivers the decision and resumes the
111
+ run.
112
+
113
+ ## Reference
114
+
115
+ - [Commands](docs/commands.md)
116
+ - [Workflow files](docs/workflow-files.md)
117
+ - [Agent definitions](docs/agent-definitions.md)
118
+
119
+ ## Development
120
+
121
+ ```sh
122
+ uv sync
123
+ uv run ruff check && uv run ruff format --check && uv run mypy && uv run pytest
124
+ ```
125
+
126
+ The dogfood workflow runs the same gate: `workgraph run wg "#<issue>"`.
@@ -0,0 +1,58 @@
1
+ [project]
2
+ name = "workgraph"
3
+ version = "0.3.3"
4
+ description = "Graph workflow orchestrator."
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ dependencies = [
10
+ "termaid[rich]>=0.8.0",
11
+ "tomlkit>=0.15.1",
12
+ ]
13
+
14
+ [project.urls]
15
+ Repository = "https://github.com/sylmarien/workgraph"
16
+ Changelog = "https://github.com/sylmarien/workgraph/blob/main/CHANGELOG.md"
17
+
18
+ [project.scripts]
19
+ workgraph = "workgraph.cli:main"
20
+
21
+ [build-system]
22
+ requires = ["uv_build>=0.8.17,<0.9.0"]
23
+ build-backend = "uv_build"
24
+
25
+ [dependency-groups]
26
+ dev = [
27
+ "mypy>=1.17",
28
+ "pytest>=8.4",
29
+ "pytest-cov>=6.2",
30
+ "python-semantic-release>=10.6.2",
31
+ "ruff>=0.12",
32
+ ]
33
+
34
+ [tool.ruff]
35
+ line-length = 100
36
+
37
+ [tool.ruff.lint]
38
+ select = ["E", "F", "W", "I", "UP", "B", "SIM"]
39
+
40
+ [tool.ruff.lint.pycodestyle]
41
+ max-line-length = 120
42
+
43
+ [tool.mypy]
44
+ strict = true
45
+ files = ["src", "tests"]
46
+
47
+ [tool.pytest.ini_options]
48
+ testpaths = ["tests"]
49
+ addopts = "--cov=workgraph --cov-report=term-missing"
50
+
51
+ [tool.coverage.report]
52
+ fail_under = 100
53
+
54
+ [tool.semantic_release]
55
+ commit_parser = "release_parser:AlwaysPatchCommitParser"
56
+ version_toml = ["pyproject.toml:project.version"]
57
+ version_variables = [".claude-plugin/plugin.json:version", ".codex-plugin/plugin.json:version"]
58
+ allow_zero_version = true
@@ -0,0 +1 @@
1
+ """Graph workflow orchestrator."""
@@ -0,0 +1,106 @@
1
+ """The Claude Code harness: argv, result reading, and transcript rendering."""
2
+
3
+ import json
4
+ import textwrap
5
+ from collections.abc import Iterator, Sequence
6
+ from contextlib import contextmanager
7
+ from typing import Any
8
+
9
+ from rich.text import Text
10
+
11
+ from workgraph.harness import (
12
+ AgentInvocation,
13
+ NodeFailure,
14
+ iter_jsonl_events,
15
+ read_last_value,
16
+ split_lines,
17
+ )
18
+
19
+
20
+ @contextmanager
21
+ def build_argv(invocation: AgentInvocation) -> Iterator[list[str]]:
22
+ """Yield the argv that runs the agent through the Claude Code CLI."""
23
+ agent_definition = invocation.agent_definition
24
+ agents = {
25
+ invocation.agent_name: {
26
+ "description": agent_definition.get("description", ""),
27
+ "prompt": agent_definition["prompt"],
28
+ }
29
+ }
30
+ # No --bare: bare mode reads no OAuth credentials, so agent nodes cannot
31
+ # authenticate for subscription users. Accepted cost: hooks and plugins
32
+ # load on every spawn.
33
+ argv = [
34
+ "claude",
35
+ "-p",
36
+ invocation.prompt,
37
+ "--output-format",
38
+ "stream-json",
39
+ "--verbose",
40
+ "--json-schema",
41
+ json.dumps(invocation.outcome_schema),
42
+ "--agents",
43
+ json.dumps(agents),
44
+ "--agent",
45
+ invocation.agent_name,
46
+ "--permission-mode",
47
+ "dontAsk",
48
+ "--model",
49
+ invocation.model,
50
+ "--effort",
51
+ invocation.effort,
52
+ ]
53
+ allowed_tools = agent_definition.get("tools", invocation.allowed_tools)
54
+ if allowed_tools is not None:
55
+ argv += ["--allowedTools", allowed_tools]
56
+ if invocation.session is not None:
57
+ # The node run continues the session in place.
58
+ argv += ["--resume", invocation.session]
59
+ yield argv
60
+
61
+
62
+ def read_result(invocation: AgentInvocation, stdout_lines: Sequence[str]) -> tuple[Any, float]:
63
+ """Return the structured output of the last result event and the cost it reports."""
64
+ agent_node_name = invocation.agent_node_name
65
+ result_events = [
66
+ event for event in iter_jsonl_events(stdout_lines) if event.get("type") == "result"
67
+ ]
68
+ if not result_events:
69
+ raise NodeFailure(f"node '{agent_node_name}': agent output holds no result event")
70
+ result_event = result_events[-1]
71
+ try:
72
+ cost = float(result_event.get("total_cost_usd") or 0)
73
+ except (TypeError, ValueError):
74
+ # A malformed cost counts as zero; the run continues.
75
+ cost = 0.0
76
+ if result_event.get("is_error"):
77
+ raise NodeFailure(f"node '{agent_node_name}': agent reported an error", cost)
78
+ return result_event.get("structured_output"), cost
79
+
80
+
81
+ def read_session(stdout_lines: Sequence[str]) -> str | None:
82
+ """Return the session id of the last stream event that carries one."""
83
+ return read_last_value(iter_jsonl_events(stdout_lines), "session_id")
84
+
85
+
86
+ def render_transcript(stdout_lines: Sequence[str]) -> list[Text]:
87
+ """Render the text blocks and tool calls of stream-json lines. Drop every other line."""
88
+ transcript_rows: list[Text] = []
89
+ for stream_event in iter_jsonl_events(stdout_lines):
90
+ if stream_event.get("type") != "assistant":
91
+ continue
92
+ for block in stream_event["message"]["content"]:
93
+ if block["type"] == "text":
94
+ transcript_rows += split_lines(block["text"])
95
+ elif block["type"] == "tool_use" and block["name"] != "StructuredOutput":
96
+ transcript_rows.append(
97
+ Text(f"▸ {block['name']}: {_summarize_tool_input(block['input'])}", "bold")
98
+ )
99
+ return transcript_rows
100
+
101
+
102
+ def _summarize_tool_input(tool_input: dict[str, Any]) -> str:
103
+ for key in ("command", "file_path", "pattern", "url"):
104
+ if key in tool_input:
105
+ return str(tool_input[key])
106
+ return textwrap.shorten(json.dumps(tool_input), 100, placeholder="...")