Skip to content

Commit 8efdcf8

Browse files
feat: add plugboard ai init CLI command (#237)
# Summary Adds a new `plugboard ai init` CLI command that creates an `AGENTS.md` file in the current working directory (or a specified directory). The file provides AI coding agents with instructions for building Plugboard models, following the convention used by tools like Claude Code, Codex, and Gemini CLI. The `AGENTS.md` template is kept in sync with `examples/AGENTS.md` via a symlink in the package. # Changes - **`plugboard/cli/ai/__init__.py`** — New CLI module with `init` command using Typer, following existing CLI patterns (rich output, stderr for errors). - **`plugboard/cli/ai/AGENTS.md`** — Symlink to `examples/AGENTS.md` so the distributed template stays in sync with the examples. - **`plugboard/cli/__init__.py`** — Register `ai` subcommand in the main CLI app. - **`tests/unit/test_cli.py`** — 3 new tests: successful creation, already-exists error, and default directory behavior. - **`docs/usage/ai.md`** — Documentation page for the new command. - **`mkdocs.yaml`** — Added "AI-Assisted Development" nav entry under Usage. - **`examples/AGENTS.md`** — Fixed two typos (`componen` → `component`, duplicate `SQLReader` → `SQLWriter`). --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: toby-coleman <13170610+toby-coleman@users.noreply.github.com> Co-authored-by: Toby Coleman <toby@tobycoleman.com>
1 parent 62a3199 commit 8efdcf8

9 files changed

Lines changed: 144 additions & 4 deletions

File tree

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,22 @@ Optional integrations for different cloud providers can be installed using `plug
6565

6666
Support for parallelisation can be installed using `plugboard[ray]`.
6767

68+
## ⚡ Quickstart with AI
69+
70+
The fastest way to get started is to let your AI coding assistant build your first model. Run the following command in your project directory:
71+
72+
```shell
73+
plugboard ai init
74+
```
75+
76+
This copies a context file (`AGENTS.md`) into your project that gives your AI tool everything it needs to know about Plugboard: how components work, how to wire them together, library components that are already available, and best practices for building models.
77+
78+
Once initialised, simply open your AI tool of choice (GitHub Copilot, Cursor, Claude, etc.) and describe the model you want to build. For example:
79+
80+
> *"I want to simulate a production line with three machines in series. Each machine has a processing time drawn from a normal distribution and a 5% chance of failure. Model the throughput over 1000 time steps and save the results to a CSV."*
81+
82+
Your AI assistant will use the `AGENTS.md` context to generate working Plugboard code — components, connectors, and a runnable process — tailored to your description.
83+
6884
## 🚀 Usage
6985

7086
<a href="https://colab.research.google.com/github/plugboard-dev/plugboard/blob/main/"><img src="https://colab.research.google.com/assets/colab-badge.svg"></a>

docs/usage/ai.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# AI-Assisted Development
2+
3+
Plugboard ships with tooling to help AI coding agents understand how to build models using the framework. The `plugboard ai` command group provides utilities for setting up AI-assisted development workflows.
4+
5+
## Initialising a project
6+
7+
The `plugboard ai init` command creates an `AGENTS.md` file in your project directory. This file gives AI coding agents the context they need to help you build Plugboard models — covering how to create components, assemble processes, use events, and follow best practices.
8+
9+
`AGENTS.md` is a convention used by AI coding tools (such as [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview), [Codex](https://openai.com/index/codex/), and [Gemini CLI](https://github.com/google-gemini/gemini-cli)) to discover project-specific instructions automatically.
10+
11+
### Usage
12+
13+
To create an `AGENTS.md` file in the current working directory:
14+
15+
```bash
16+
plugboard ai init
17+
```
18+
19+
To create the file in a specific directory:
20+
21+
```bash
22+
plugboard ai init /path/to/project
23+
```
24+
25+
!!! note
26+
The command will not overwrite an existing `AGENTS.md` file. If one already exists in the target directory, the command exits with an error.
27+
28+
### What's in the file?
29+
30+
The generated `AGENTS.md` covers:
31+
32+
- **Planning a model** — how to break a problem down into components, inputs, outputs, and data flows.
33+
- **Implementing components** — using built-in library components and creating custom ones by subclassing [`Component`][plugboard.component.Component].
34+
- **Assembling a process** — connecting components together and running a [`LocalProcess`][plugboard.process.LocalProcess].
35+
- **Event-driven models** — defining custom [`Event`][plugboard.events.Event] types, emitting events, and writing event handlers.
36+
- **Exporting models** — saving process definitions to YAML and running them via the CLI.
37+
38+
The file is intended to be committed to version control alongside your project code so that any AI agent working in the repository has immediate access to Plugboard conventions.
39+
40+
### Customising
41+
42+
After generating the file you can edit it freely to add project-specific instructions — for example, domain context, coding standards, or pointers to your own components and data sources.

examples/AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Ask questions if anything is not clear about the business logic or you require a
2020

2121
Always check whether the functionality you need is already available in the library components in `plugboard.library`. For example, try to use:
2222
- `FileReader` and `FileWriter` for reading/writing data from CSV or parquet files.
23-
- `SQLReader` and `SQLReader` for reading/writing data from SQL databases.
23+
- `SQLReader` and `SQLWriter` for reading/writing data from SQL databases.
2424
- `LLMChat` for interacting with standard LLMs, e.g. OpenAI, Gemini, etc.
2525

2626
**Using Built-in Components**
@@ -33,7 +33,7 @@ data_loader = FileReader(name="input_data", path="input.csv", field_names=["x",
3333

3434
**Creating Custom Components**
3535

36-
New components should inherit from `plugboard.componen.Component`. Add logging messages where it would be helpful by using the bound logger `self._logger`.
36+
New components should inherit from `plugboard.component.Component`. Add logging messages where it would be helpful by using the bound logger `self._logger`.
3737

3838
```python
3939
import typing as _t

mkdocs.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ nav:
129129
- Event-driven models: examples/tutorials/event-driven-models.md
130130
- Tuning a process: examples/tutorials/tuning-a-process.md
131131
- Configuration: usage/configuration.md
132+
- AI-Assisted Development: usage/ai.md
132133
- Topics: usage/topics.md
133134
- Demos:
134135
- Fundamentals:

plugboard/cli/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import typer
44

55
from plugboard import __version__
6+
from plugboard.cli.ai import app as ai_app
67
from plugboard.cli.process import app as process_app
78
from plugboard.cli.server import app as server_app
89
from plugboard.cli.version import app as version_app
@@ -14,6 +15,7 @@
1415
help=f"[bold]Plugboard CLI[/bold]\n\nVersion {__version__}",
1516
pretty_exceptions_show_locals=False,
1617
)
18+
app.add_typer(ai_app, name="ai")
1719
app.add_typer(process_app, name="process")
1820
app.add_typer(server_app, name="server")
1921
app.add_typer(version_app, name="version")

plugboard/cli/ai/AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../examples/AGENTS.md

plugboard/cli/ai/__init__.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""Plugboard AI CLI."""
2+
3+
from pathlib import Path
4+
import shutil
5+
6+
from rich import print
7+
from rich.console import Console
8+
import typer
9+
10+
11+
app = typer.Typer(
12+
rich_markup_mode="rich", no_args_is_help=True, pretty_exceptions_show_locals=False
13+
)
14+
stderr = Console(stderr=True)
15+
16+
_AGENTS_MD = Path(__file__).parent / "AGENTS.md"
17+
18+
19+
@app.command()
20+
def init(
21+
directory: Path = typer.Argument(
22+
default=None,
23+
help="Target directory for the AGENTS.md file. Defaults to the current working directory.",
24+
exists=True,
25+
file_okay=False,
26+
dir_okay=True,
27+
resolve_path=True,
28+
),
29+
) -> None:
30+
"""Initialise a project with an AGENTS.md file for AI-assisted development."""
31+
if directory is None:
32+
directory = Path.cwd()
33+
34+
target = directory / "AGENTS.md"
35+
36+
if target.exists():
37+
stderr.print("[red]AGENTS.md already exists[/red] in the target directory.")
38+
raise typer.Exit(1)
39+
40+
shutil.copy2(_AGENTS_MD, target)
41+
print(f"[green]Created[/green] {target}")

plugboard/tune/tune.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
"""Provides `Tuner` class for optimising Plugboard processes."""
22

3+
from __future__ import annotations
4+
35
from functools import partial
46
from inspect import isfunction, signature
57
import math
68
from pydoc import locate
79
import typing as _t
810

9-
import ray.tune.search.optuna
10-
1111
from plugboard.component.component import Component, ComponentRegistry
1212
from plugboard.exceptions import ConstraintError
1313
from plugboard.process import Process, ProcessBuilder
@@ -27,6 +27,7 @@
2727
import optuna.storages
2828
import ray.tune
2929
import ray.tune.search
30+
import ray.tune.search.optuna
3031
except ImportError: # pragma: no cover
3132
pass
3233

tests/unit/test_cli.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,42 @@ def test_cli_process_diagram() -> None:
8787
assert "flowchart" in result.stdout
8888

8989

90+
def test_cli_ai_init(tmp_path: Path) -> None:
91+
"""Tests the ai init command creates AGENTS.md."""
92+
result = runner.invoke(app, ["ai", "init", str(tmp_path)])
93+
assert result.exit_code == 0
94+
assert "Created" in result.stdout
95+
# File must exist with expected content
96+
agents_md = tmp_path / "AGENTS.md"
97+
assert agents_md.exists()
98+
content = agents_md.read_text()
99+
assert "Plugboard" in content
100+
101+
102+
def test_cli_ai_init_already_exists(tmp_path: Path) -> None:
103+
"""Tests the ai init command fails when AGENTS.md already exists."""
104+
(tmp_path / "AGENTS.md").write_text("existing content")
105+
result = runner.invoke(app, ["ai", "init", str(tmp_path)])
106+
assert result.exit_code == 1
107+
# Error is printed to stderr which typer captures in output
108+
assert "already exists" in result.output
109+
110+
111+
def test_cli_ai_init_default_directory() -> None:
112+
"""Tests the ai init command uses current directory by default."""
113+
with tempfile.TemporaryDirectory() as tmpdir:
114+
original_cwd = Path.cwd()
115+
try:
116+
import os
117+
118+
os.chdir(tmpdir)
119+
result = runner.invoke(app, ["ai", "init"])
120+
assert result.exit_code == 0
121+
assert (Path(tmpdir) / "AGENTS.md").exists()
122+
finally:
123+
os.chdir(original_cwd)
124+
125+
90126
def test_cli_server_discover(test_project_dir: Path) -> None:
91127
"""Tests the server discover command."""
92128
with respx.mock:

0 commit comments

Comments
 (0)