Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
15b9e8b
rewrite planoai CLI in Rust
adilhafeez Mar 22, 2026
1e6f38f
fix validate-config CI job to use Python (script unchanged)
adilhafeez Mar 22, 2026
eb30c65
add install.sh script and self-update command
adilhafeez Mar 22, 2026
6efb152
add validate command, remove Python dependency from CI
adilhafeez Mar 22, 2026
5a1de47
build CLI once, share binary via artifact across CI jobs
adilhafeez Mar 22, 2026
a0e0f0f
revert validate-config to Python (Tera indent() compat needs fixing)
adilhafeez Mar 22, 2026
b1486a9
revert native-smoke-test to Python CLI (Tera template compat pending)
adilhafeez Mar 22, 2026
b7fd777
fix Docker build: add plano-cli to workspace manifest in Dockerfile
adilhafeez Mar 22, 2026
cc896bf
fix Tera template compat, remove Python from CI entirely
adilhafeez Mar 22, 2026
f63d86f
simplify validate script, drop rendered file diff check
adilhafeez Mar 23, 2026
0ee45e7
update README with install.sh instructions
adilhafeez Mar 23, 2026
944cddd
update quickstart with install.sh instructions
adilhafeez Mar 23, 2026
e4af53a
add dev install instructions to quickstart and contributing guide
adilhafeez Mar 23, 2026
7055081
fix Tera indent filter to match Jinja2 behavior (skip first line)
adilhafeez Mar 23, 2026
be99690
fix daemon process detach: use process_group(0) to prevent SIGTERM on…
adilhafeez Mar 23, 2026
fde90a0
fix daemon detach: use setsid() and add sleep in CI smoke test
adilhafeez Mar 23, 2026
e8dd0bb
merge start and health check into single CI step to avoid process cle…
adilhafeez Mar 23, 2026
2e3744f
use double-fork daemon to fully detach child processes
adilhafeez Mar 23, 2026
6cf0c4f
remove Python from Docker: use Rust CLI for config generation
adilhafeez Mar 23, 2026
f59794d
remove Python CLI from all CI jobs, use Rust binary artifact everywhere
adilhafeez Mar 23, 2026
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
9 changes: 4 additions & 5 deletions .claude/skills/build-cli/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
---
name: build-cli
description: Build and install the Python CLI (planoai). Use after making changes to cli/ code to install locally.
description: Build and install the Rust CLI (planoai). Use after making changes to plano-cli code to install locally.
---

1. `cd cli && uv sync` — ensure dependencies are installed
2. `cd cli && uv tool install --editable .` — install the CLI locally
3. Verify the installation: `cd cli && uv run planoai --help`
1. `cd crates && cargo build --release -p plano-cli` — build the CLI binary
2. Verify the installation: `./crates/target/release/planoai --help`

If the build or install fails, diagnose and fix the issues.
If the build fails, diagnose and fix the issues.
179 changes: 88 additions & 91 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,72 +25,62 @@ jobs:
- uses: pre-commit/action@v3.0.1

# ──────────────────────────────────────────────
# Plano tools (CLI) tests — no Docker needed
# Plano CLI (Rust) tests — no Docker needed
# ──────────────────────────────────────────────
plano-tools-tests:
plano-cli-tests:
runs-on: ubuntu-latest-m
defaults:
run:
working-directory: ./cli
steps:
- uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.14"

- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh

- name: Install plano tools
run: uv sync --extra dev
- name: Install Rust
uses: dtolnay/rust-toolchain@stable

- name: Sync CLI templates to demos
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: uv run python -m planoai.template_sync
- name: Build and test plano-cli
working-directory: ./crates
run: |
cargo test -p plano-cli
cargo build --release -p plano-cli

- name: Run tests
run: uv run pytest
- name: Upload planoai binary
uses: actions/upload-artifact@v6
with:
name: planoai-binary
path: crates/target/release/planoai
retention-days: 1

# ──────────────────────────────────────────────
# Native mode smoke test — build from source & start natively
# ──────────────────────────────────────────────
native-smoke-test:
needs: plano-cli-tests
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-wasip1

- name: Install planoai CLI
working-directory: ./cli
run: |
uv sync
uv tool install .
- name: Download planoai binary
uses: actions/download-artifact@v6
with:
name: planoai-binary
path: crates/target/release/

- name: Make binary executable
run: chmod +x crates/target/release/planoai

- name: Build native binaries
run: planoai build
run: crates/target/release/planoai build

- name: Start plano natively
- name: Start plano and health check
env:
OPENAI_API_KEY: test-key-not-used
run: planoai up tests/e2e/config_native_smoke.yaml

- name: Health check
run: |
crates/target/release/planoai up tests/e2e/config_native_smoke.yaml
sleep 3
for i in $(seq 1 30); do
if curl -sf http://localhost:12000/healthz > /dev/null 2>&1; then
echo "Health check passed"
Expand All @@ -105,7 +95,7 @@ jobs:

- name: Stop plano
if: always()
run: planoai down || true
run: crates/target/release/planoai down || true

# ──────────────────────────────────────────────
# Single Docker build — shared by all downstream jobs
Expand Down Expand Up @@ -152,21 +142,25 @@ jobs:
# Validate plano config
# ──────────────────────────────────────────────
validate-config:
needs: plano-cli-tests
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
- name: Download planoai binary
uses: actions/download-artifact@v6
with:
python-version: "3.14"
name: planoai-binary
path: crates/target/release/

- name: Install planoai
run: pip install -e ./cli
- name: Make binary executable
run: chmod +x crates/target/release/planoai

- name: Validate plano config
run: bash config/validate_plano_config.sh
run: |
export PATH="$PWD/crates/target/release:$PATH"
bash config/validate_plano_config.sh

# ──────────────────────────────────────────────
# Docker security scan (Trivy)
Expand Down Expand Up @@ -216,7 +210,7 @@ jobs:
# E2E: prompt_gateway tests
# ──────────────────────────────────────────────
test-prompt-gateway:
needs: docker-build
needs: [docker-build, plano-cli-tests]
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand All @@ -237,6 +231,15 @@ jobs:
- name: Load plano image
run: docker load -i /tmp/plano-image.tar

- name: Download planoai binary
uses: actions/download-artifact@v6
with:
name: planoai-binary
path: /usr/local/bin/

- name: Make binary executable
run: chmod +x /usr/local/bin/planoai

- name: Set up Python
uses: actions/setup-python@v6
with:
Expand All @@ -246,9 +249,7 @@ jobs:
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
cache-dependency-glob: |
tests/e2e/uv.lock
cli/uv.lock
cache-dependency-glob: tests/e2e/uv.lock

- name: Run prompt_gateway tests
env:
Expand All @@ -266,7 +267,7 @@ jobs:
# E2E: model_alias_routing tests
# ──────────────────────────────────────────────
test-model-alias-routing:
needs: docker-build
needs: [docker-build, plano-cli-tests]
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand All @@ -287,6 +288,15 @@ jobs:
- name: Load plano image
run: docker load -i /tmp/plano-image.tar

- name: Download planoai binary
uses: actions/download-artifact@v6
with:
name: planoai-binary
path: /usr/local/bin/

- name: Make binary executable
run: chmod +x /usr/local/bin/planoai

- name: Set up Python
uses: actions/setup-python@v6
with:
Expand All @@ -296,9 +306,7 @@ jobs:
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
cache-dependency-glob: |
tests/e2e/uv.lock
cli/uv.lock
cache-dependency-glob: tests/e2e/uv.lock

- name: Run model alias routing tests
env:
Expand All @@ -316,7 +324,7 @@ jobs:
# E2E: responses API with state tests
# ──────────────────────────────────────────────
test-responses-api-with-state:
needs: docker-build
needs: [docker-build, plano-cli-tests]
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand All @@ -337,6 +345,15 @@ jobs:
- name: Load plano image
run: docker load -i /tmp/plano-image.tar

- name: Download planoai binary
uses: actions/download-artifact@v6
with:
name: planoai-binary
path: /usr/local/bin/

- name: Make binary executable
run: chmod +x /usr/local/bin/planoai

- name: Set up Python
uses: actions/setup-python@v6
with:
Expand All @@ -346,9 +363,7 @@ jobs:
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
cache-dependency-glob: |
tests/e2e/uv.lock
cli/uv.lock
cache-dependency-glob: tests/e2e/uv.lock

- name: Run responses API with state tests
env:
Expand Down Expand Up @@ -431,17 +446,12 @@ jobs:
# E2E: demo — preference based routing
# ──────────────────────────────────────────────
e2e-demo-preference:
needs: docker-build
needs: [docker-build, plano-cli-tests]
runs-on: ubuntu-latest-m
steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.14"

- name: Download plano image
uses: actions/download-artifact@v7
with:
Expand All @@ -451,23 +461,20 @@ jobs:
- name: Load plano image
run: docker load -i /tmp/plano-image.tar

- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Download planoai binary
uses: actions/download-artifact@v6
with:
name: planoai-binary
path: /usr/local/bin/

- name: Setup python venv
run: python -m venv venv
- name: Make binary executable
run: chmod +x /usr/local/bin/planoai

- name: Install hurl
run: |
curl --location --remote-name https://github.com/Orange-OpenSource/hurl/releases/download/4.0.0/hurl_4.0.0_amd64.deb
sudo dpkg -i hurl_4.0.0_amd64.deb

- name: Install plano gateway and test dependencies
run: |
source venv/bin/activate
cd cli && echo "installing plano cli" && uv sync && uv tool install .
cd ../demos/shared/test_runner && echo "installing test dependencies" && uv sync

- name: Run demo tests
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
Expand All @@ -476,24 +483,18 @@ jobs:
ARCH_API_KEY: ${{ secrets.ARCH_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
source venv/bin/activate
cd demos/shared/test_runner && sh run_demo_tests.sh llm_routing/preference_based_routing

# ──────────────────────────────────────────────
# E2E: demo — currency conversion
# ──────────────────────────────────────────────
e2e-demo-currency:
needs: docker-build
needs: [docker-build, plano-cli-tests]
runs-on: ubuntu-latest-m
steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.14"

- name: Download plano image
uses: actions/download-artifact@v7
with:
Expand All @@ -503,28 +504,24 @@ jobs:
- name: Load plano image
run: docker load -i /tmp/plano-image.tar

- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Download planoai binary
uses: actions/download-artifact@v6
with:
name: planoai-binary
path: /usr/local/bin/

- name: Setup python venv
run: python -m venv venv
- name: Make binary executable
run: chmod +x /usr/local/bin/planoai

- name: Install hurl
run: |
curl --location --remote-name https://github.com/Orange-OpenSource/hurl/releases/download/4.0.0/hurl_4.0.0_amd64.deb
sudo dpkg -i hurl_4.0.0_amd64.deb

- name: Install plano gateway and test dependencies
run: |
source venv/bin/activate
cd cli && echo "installing plano cli" && uv sync && uv tool install .
cd ../demos/shared/test_runner && echo "installing test dependencies" && uv sync

- name: Run demo tests
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
run: |
source venv/bin/activate
cd demos/shared/test_runner && sh run_demo_tests.sh advanced/currency_exchange
Loading
Loading