Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/cli/acw.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ acw --help

## Description

`acw` provides a consistent interface for invoking different AI CLI tools (claude, codex, opencode, cursor/agent) with file-based input/output. Optional flags allow editor-based input and stdout output while preserving the default file-based workflow. Python workflows wrap `acw` through `agentize.workflow.utils.acw` to preserve the same invocation semantics and timing logs.
`acw` provides a consistent interface for invoking different AI CLI tools (claude, codex, opencode, cursor/agent) with file-based input/output. Optional flags allow editor-based input and stdout output while preserving the default file-based workflow. Python workflows wrap `acw` through `agentize.workflow.api.acw` to preserve the same invocation semantics and timing logs.

## Arguments

Expand Down
2 changes: 1 addition & 1 deletion docs/cli/lol.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ lol <command> [options]
python -m agentize.cli <command> [options]
```

The Python entrypoint delegates to shell functions for most commands. `lol impl` runs the Python workflow implementation, and the shell `impl.sh` delegates to it. `lol` is the only public shell entrypoint; helper functions are private implementation details. Use the Python entrypoint for non-sourced environments or scripting contexts where argparse-style parsing is preferred.
The Python entrypoint delegates to shell functions for most commands. `lol impl` runs the Python workflow implementation (via `agentize.workflow.api`), and the shell `impl.sh` delegates to it. `lol` is the only public shell entrypoint; helper functions are private implementation details. Use the Python entrypoint for non-sourced environments or scripting contexts where argparse-style parsing is preferred.

## Commands

Expand Down
2 changes: 1 addition & 1 deletion docs/cli/planner.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Each stage uses `acw` for file-based CLI invocation. Prompts are rendered at run
- Plan-guideline content (from `.claude-plugin/skills/plan-guideline/SKILL.md`, YAML frontmatter stripped)
- Feature description and previous stage output

Prompt templates are rendered via `agentize.workflow.utils.prompt.render`, which replaces both `{{TOKEN}}` and `{#TOKEN#}` placeholders without requiring template format changes.
Prompt templates are rendered via `agentize.workflow.api.prompt.render`, which replaces both `{{TOKEN}}` and `{#TOKEN#}` placeholders without requiring template format changes.

The consensus stage renders a dedicated prompt from `.claude-plugin/skills/external-consensus/external-review-prompt.md` with the three report outputs embedded.

Expand Down
3 changes: 2 additions & 1 deletion docs/feat/draft/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Define a lightweight, imperative workflow API for coordinating agent sessions, w
- output validation
- retry with configurable attempts
- consistent errors
- optional input/output path overrides for workflows that reuse fixed artifacts
- `Session.run_parallel(...)` runs multiple sessions concurrently with the **same retry policy**.
- `Session.stage(...)` builds a lightweight call object for `run_parallel(...)`.
- `StageResult` exposes `stage`, `input_path`, `output_path`, and `process` with a `.text()` helper.
Expand Down Expand Up @@ -72,7 +73,7 @@ python/agentize/workflow/api/

- **Constructor**: `Session(output_dir, prefix, *, runner=run_acw, input_suffix="-input.md", output_suffix="-output.md")`
- **run_prompt**:
- `run_prompt(name, prompt, backend, *, tools=None, permission_mode=None, timeout=3600, extra_flags=None, retry=0, retry_delay=0) -> StageResult`
- `run_prompt(name, prompt, backend, *, tools=None, permission_mode=None, timeout=3600, extra_flags=None, retry=0, retry_delay=0, input_path=None, output_path=None) -> StageResult`
- Writes input file, runs ACW, validates output, retries on failure.
- **stage**:
- `stage(name, prompt, backend, **opts) -> StageCall`
Expand Down
4 changes: 2 additions & 2 deletions python/agentize/workflow/__init__.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Public interfaces for Python planner and impl workflow orchestration.

## External Interfaces

### From `utils/`
### From `api/`

#### `run_acw`

Expand Down Expand Up @@ -143,7 +143,7 @@ This module re-exports interfaces from submodules and does not define internal h

| Module | Purpose |
|--------|---------|
| `utils/` | Helper package for ACW invocation, GitHub operations, prompt rendering, and path resolution |
| `api/` | Public workflow API including Session DSL and helper utilities |
| `planner/` | Standalone planning pipeline package (`python -m agentize.workflow.planner`) |
| `planner.py` | Backward-compatible re-exports (deprecated) |
| `impl/` | Issue-to-implementation workflow (Python) with file-based prompt |
Expand Down
2 changes: 1 addition & 1 deletion python/agentize/workflow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from agentize.workflow.impl import ImplError, run_impl_workflow
from agentize.workflow.planner import StageResult, run_planner_pipeline
from agentize.workflow.utils import ACW, run_acw
from agentize.workflow.api import ACW, run_acw

__all__ = [
"ImplError",
Expand Down
13 changes: 13 additions & 0 deletions python/agentize/workflow/api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Workflow API Package

Public workflow API for building imperative agent pipelines. This package exposes the Session DSL alongside shared helpers for ACW invocation, prompt rendering, GitHub automation, and path resolution.

## Organization

- `__init__.py` - Convenience re-exports for public API symbols
- `session.py` - Session DSL for running staged workflows (single and parallel)
- `acw.py` - ACW invocation helpers with timing logs and provider validation
- `gh.py` - GitHub CLI wrappers for issue/label/PR actions
- `prompt.py` - Prompt rendering for `{#TOKEN#}` and `{{TOKEN}}` placeholders
- `path.py` - Path resolution helper relative to a module file
- Companion `.md` files document interfaces and internal helpers
112 changes: 112 additions & 0 deletions python/agentize/workflow/api/__init__.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Module: agentize.workflow.api

Public workflow API surface providing the Session DSL and ACW helpers.

## External Interfaces

### `Session`

```python
class Session:
def __init__(...): ...
def run_prompt(...): ...
def stage(...): ...
def run_parallel(...): ...
```

Re-export of `agentize.workflow.api.session.Session`.

### `StageResult`

```python
@dataclass
class StageResult:
stage: str
input_path: Path
output_path: Path
process: subprocess.CompletedProcess
```

Re-export of `agentize.workflow.api.session.StageResult`.

### `StageCall`

```python
@dataclass
class StageCall:
stage: str
prompt: str | Callable[[Path], str]
backend: tuple[str, str]
options: dict[str, Any]
```

Re-export of `agentize.workflow.api.session.StageCall`.

### `PipelineError`

```python
class PipelineError(RuntimeError): ...
```

Re-export of `agentize.workflow.api.session.PipelineError`.

### `run_acw`

```python
def run_acw(
provider: str,
model: str,
input_file: str | Path,
output_file: str | Path,
*,
tools: str | None = None,
permission_mode: str | None = None,
extra_flags: list[str] | None = None,
timeout: int = 3600,
cwd: str | Path | None = None,
env: dict[str, str] | None = None,
) -> subprocess.CompletedProcess
```

Re-export of `agentize.workflow.api.acw.run_acw`.

### `list_acw_providers`

```python
def list_acw_providers() -> list[str]
```

Re-export of `agentize.workflow.api.acw.list_acw_providers`.

### `ACW`

```python
class ACW:
def __init__(
self,
name: str,
provider: str,
model: str,
timeout: int = 900,
*,
tools: str | None = None,
permission_mode: str | None = None,
extra_flags: list[str] | None = None,
log_writer: Callable[[str], None] | None = None,
runner: Callable[..., subprocess.CompletedProcess] | None = None,
) -> None: ...
def run(self, input_file: str | Path, output_file: str | Path) -> subprocess.CompletedProcess: ...
```

Re-export of `agentize.workflow.api.acw.ACW`.

## Internal Helpers

This module only re-exports selected helpers and does not define its own internal
implementation.

## Design Rationale

- **Single entry point**: A stable import surface for the Session DSL and ACW helpers.
- **Focused exports**: Re-exports stay limited to workflow primitives without exposing
internal convenience logic from other packages.
16 changes: 16 additions & 0 deletions python/agentize/workflow/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""Public workflow API: Session DSL plus ACW helpers."""

from __future__ import annotations

from agentize.workflow.api.acw import ACW, list_acw_providers, run_acw
from agentize.workflow.api.session import PipelineError, Session, StageCall, StageResult

__all__ = [
"ACW",
"list_acw_providers",
"run_acw",
"Session",
"StageCall",
"StageResult",
"PipelineError",
]
138 changes: 138 additions & 0 deletions python/agentize/workflow/api/session.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# session.py

Session DSL for running staged agent workflows with consistent artifact handling, retries, and parallel execution.

## External Interface

### `Session`

```python
def __init__(
self,
output_dir: str | Path,
prefix: str,
*,
runner: Callable[..., subprocess.CompletedProcess] = run_acw,
input_suffix: str = "-input.md",
output_suffix: str = "-output.md",
) -> None
```

**Purpose**: Configure a workflow session rooted at `output_dir` with a shared artifact prefix and an injectable ACW runner.

**Parameters**:
- `output_dir`: Directory for input/output artifacts (created if missing).
- `prefix`: Filename prefix used when input/output paths are not overridden.
- `runner`: ACW-compatible callable (defaults to `run_acw`).
- `input_suffix`: Default suffix for generated input filenames.
- `output_suffix`: Default suffix for generated output filenames.

### `Session.run_prompt()`

```python
def run_prompt(
self,
name: str,
prompt: str | Callable[[Path], str],
backend: tuple[str, str],
*,
tools: str | None = None,
permission_mode: str | None = None,
timeout: int = 3600,
extra_flags: list[str] | None = None,
retry: int = 0,
retry_delay: float = 0,
input_path: str | Path | None = None,
output_path: str | Path | None = None,
) -> StageResult
```

Runs a single stage with retries and output validation.

**Behavior**:
- Resolves input/output paths from `prefix` + suffixes unless overrides are provided.
- Writes the prompt to the input path (string content or a writer callable).
- Executes the runner with stage-level tools and permission mode.
- Validates output (non-zero exit, missing output, or empty output triggers retry).
- Retries up to `1 + retry` attempts; raises `PipelineError` on failure.

### `Session.stage()`

```python
def stage(
self,
name: str,
prompt: str | Callable[[Path], str],
backend: tuple[str, str],
**opts: Any,
) -> StageCall
```

Creates a lightweight stage call object for `run_parallel()`.

### `Session.run_parallel()`

```python
def run_parallel(
self,
calls: Iterable[StageCall],
*,
max_workers: int = 2,
retry: int = 0,
retry_delay: float = 0,
) -> dict[str, StageResult]
```

Runs multiple stages concurrently with a shared retry policy and returns results keyed by stage name.

### `StageResult`

```python
@dataclass
class StageResult:
stage: str
input_path: Path
output_path: Path
process: subprocess.CompletedProcess

def text(self) -> str: ...
```

Represents a successful stage execution. `.text()` reads the output file as a string.

### `StageCall`

```python
@dataclass
class StageCall:
stage: str
prompt: str | Callable[[Path], str]
backend: tuple[str, str]
options: dict[str, Any]
```

Captures the inputs for a stage scheduled via `run_parallel()`.

### `PipelineError`

```python
class PipelineError(RuntimeError):
stage: str
attempts: int
last_error: Exception | str
```

Raised after retry exhaustion, carrying stage metadata and the last failure detail.

## Internal Helpers

- `_resolve_paths()`: Applies default suffixes and normalizes path overrides.
- `_write_prompt()`: Writes prompt content to the input artifact path.
- `_run_with_retries()`: Encapsulates retry loop and validation checks.
- `_validate_output()`: Ensures successful exit code and non-empty output.

## Design Rationale

- **Consistent artifacts**: Centralized path resolution ensures predictable filenames and keeps workflows focused on orchestration logic.
- **Shared validation**: Output checks and retries live in one place to avoid duplicated error handling across pipelines.
- **Minimal concurrency**: A small `run_parallel()` wrapper covers the common fan-out use case without adding heavy orchestration layers.
Loading