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
46 changes: 46 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: CI

on:
push:
branches:
- main
pull_request:

jobs:
rust:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Rust
uses: dtolnay/rust-toolchain@stable

- name: Cache Cargo
uses: Swatinem/rust-cache@v2

- name: Run Rust tests
run: cargo test

- name: Run Rust serde tests
run: cargo test --features serde

ui:
runs-on: ubuntu-latest
defaults:
run:
working-directory: web/void-control-ux
steps:
- uses: actions/checkout@v4

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: web/void-control-ux/package-lock.json

- name: Install UI dependencies
run: npm ci

- name: Build UI
run: npm run build
152 changes: 152 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
name: Release

on:
push:
tags:
- 'v*.*.*'

permissions:
contents: write

jobs:
verify-version:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v4

- name: Verify manifest versions match tag
id: version
run: |
TAG="${GITHUB_REF_NAME#v}"
CARGO_VERSION=$(python3 - <<'PY'
from pathlib import Path
for line in Path("Cargo.toml").read_text().splitlines():
if line.startswith("version = "):
print(line.split('"')[1])
break
PY
)
UI_VERSION=$(python3 - <<'PY'
import json
from pathlib import Path
print(json.loads(Path("web/void-control-ux/package.json").read_text())["version"])
PY
)
test "${TAG}" = "${CARGO_VERSION}"
test "${TAG}" = "${UI_VERSION}"
echo "version=${TAG}" >> "$GITHUB_OUTPUT"

rust-release:
runs-on: ubuntu-latest
needs: verify-version
steps:
- uses: actions/checkout@v4

- name: Set up Rust
uses: dtolnay/rust-toolchain@stable

- name: Cache Cargo
uses: Swatinem/rust-cache@v2

- name: Build release binaries
run: |
cargo test
cargo test --features serde
cargo build --release --features serde --bin voidctl --bin normalize_fixture

- name: Package voidctl
run: |
mkdir -p dist/voidctl
cp target/release/voidctl dist/voidctl/
cp README.md LICENSE dist/voidctl/
tar -C dist -czf "voidctl-v${{ needs.verify-version.outputs.version }}-x86_64-unknown-linux-gnu.tar.gz" voidctl

- name: Package normalize_fixture
run: |
mkdir -p dist/normalize_fixture
cp target/release/normalize_fixture dist/normalize_fixture/
cp README.md LICENSE dist/normalize_fixture/
tar -C dist -czf "normalize_fixture-v${{ needs.verify-version.outputs.version }}-x86_64-unknown-linux-gnu.tar.gz" normalize_fixture

- name: Upload Rust release artifacts
uses: actions/upload-artifact@v4
with:
name: rust-release-assets
path: |
voidctl-v${{ needs.verify-version.outputs.version }}-x86_64-unknown-linux-gnu.tar.gz
normalize_fixture-v${{ needs.verify-version.outputs.version }}-x86_64-unknown-linux-gnu.tar.gz

ui-release:
runs-on: ubuntu-latest
needs: verify-version
defaults:
run:
working-directory: web/void-control-ux
steps:
- uses: actions/checkout@v4

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: web/void-control-ux/package-lock.json

- name: Install UI dependencies
run: npm ci

- name: Build UI
run: npm run build

- name: Package UI bundle
run: |
tar -C dist -czf "../../void-control-ux-v${{ needs.verify-version.outputs.version }}.tar.gz" .

- name: Upload UI release artifact
uses: actions/upload-artifact@v4
with:
name: ui-release-asset
path: void-control-ux-v${{ needs.verify-version.outputs.version }}.tar.gz

publish-release:
runs-on: ubuntu-latest
needs:
- verify-version
- rust-release
- ui-release
steps:
- uses: actions/checkout@v4

- name: Download Rust release assets
uses: actions/download-artifact@v4
with:
name: rust-release-assets
path: release-assets

- name: Download UI release asset
uses: actions/download-artifact@v4
with:
name: ui-release-asset
path: release-assets

- name: Prepare release notes header
run: |
cat > .github-release-notes.md <<'EOF'
First public `void-control` release.

Supported `void-box` baseline for this release:
- `void-box` `v0.1.1` or equivalent validated production build

Included assets:
- `voidctl` Linux x86_64 binary archive
- `normalize_fixture` Linux x86_64 binary archive
- `void-control-ux` production bundle archive
EOF

- name: Publish GitHub Release
uses: softprops/action-gh-release@v2
with:
files: release-assets/*
body_path: .github-release-notes.md
33 changes: 33 additions & 0 deletions .github/workflows/void-box-compatibility.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Void Box Compatibility

on:
workflow_dispatch:
inputs:
void_box_base_url:
description: 'Reachable void-box daemon URL'
required: true
default: 'http://127.0.0.1:43100'
supported_void_box_version:
description: 'Validated void-box version/build label'
required: true
default: 'v0.1.1'

jobs:
compatibility:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4

- name: Set up Rust
uses: dtolnay/rust-toolchain@stable

- name: Cache Cargo
uses: Swatinem/rust-cache@v2

- name: Report compatibility target
run: |
echo "Validating against void-box baseline: ${{ inputs.supported_void_box_version }}"
echo "Daemon URL: ${{ inputs.void_box_base_url }}"

- name: Run compatibility gate
run: scripts/release/check_void_box_compat.sh "${{ inputs.void_box_base_url }}"
37 changes: 19 additions & 18 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
# Generated by Cargo
# will have compiled files and executables
debug
target
/target
/artifacts
/tmp
package-lock.json
package.json
node_modules
.claude
.idea
.local-utils

# These are backup files generated by rustfmt
**/*.rs.bk
# Frontend build output and local env files
web/void-control-ux/dist/
web/void-control-ux/.env
web/void-control-ux/.env.local
web/void-control-ux/.env.*.local
web/void-control-ux/tmp_*.mjs

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
.github-release-notes.md

# Generated by cargo mutants
# Contains mutation testing data
**/mutants.out*/

# RustRover
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# Keep the UI lockfile tracked for CI/npm ci
!web/void-control-ux/package.json
!web/void-control-ux/package-lock.json
120 changes: 120 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Repository Guidelines

## Project Structure & Module Organization
This repository currently contains architecture and runtime-contract documentation for Void Control.

- `spec/`: Canonical specifications (for example, `spec/void-control-runtime-spec-v0.1.md`).
- `LICENSE`: Project license.

When adding implementation code, keep the same separation of concerns defined in the spec:
- Control-plane orchestration logic should be separate from runtime execution logic.
- Add new specs to `spec/` and version them in the filename (for example, `*-v0.2.md`).

## Build, Test, and Development Commands
Use Cargo for local development and validation:

- `cargo test`: Run core unit tests (no optional JSON compatibility feature).
- `cargo test --features serde`: Run JSON compatibility tests and fixture-based checks.
- `cargo test --features serde runtime::void_box::`: Run live-daemon client contract tests (mocked transport).
- `VOID_BOX_BASE_URL=http://127.0.0.1:3000 cargo test --features serde --test void_box_contract -- --ignored --nocapture`: Run live daemon contract gate tests (tests auto-generate fallback specs under `/tmp`).
- Optional spec overrides for policy behavior checks:
- `VOID_BOX_TIMEOUT_SPEC_FILE`
- `VOID_BOX_PARALLEL_SPEC_FILE`
- `VOID_BOX_RETRY_SPEC_FILE`
- `VOID_BOX_NO_POLICY_SPEC_FILE`
- `cargo run --example normalize_void_box_run`: Run the typed normalization example.
- `cargo run --bin normalize_fixture -- fixtures/sample.vbrun`: Normalize from local fixture format.

### Void-Box Production Image (for UI/real Claude runs)

When validating real pipeline execution from `void-control` UI, use the production
void-box rootfs from the sibling repository:

```bash
cd /home/diego/github/agent-infra/void-box
TMPDIR=$PWD/target/tmp scripts/build_claude_rootfs.sh
```

Start daemon with production kernel/initramfs:

```bash
cd /home/diego/github/agent-infra/void-box
export ANTHROPIC_API_KEY=sk-ant-...
export VOID_BOX_KERNEL=/boot/vmlinuz-$(uname -r)
export VOID_BOX_INITRAMFS=$PWD/target/void-box-rootfs.cpio.gz
cargo run --bin voidbox -- serve --listen 127.0.0.1:43100
```

Start bridge (required for Launch modal spec upload/content mode):

```bash
cd /home/diego/github/void-control
cargo run --features serde --bin voidctl -- serve
```

Start UI:

```bash
cd /home/diego/github/void-control/web/void-control-ux
npm run dev -- --host 127.0.0.1 --port 3000
```

Important:
- Do not use `/tmp/void-box-test-rootfs.cpio.gz` for production/runtime UI validation.
- `target/void-box-rootfs.cpio.gz` is the expected production image path.

### UI Debugging Requirement

For UI work in `web/void-control-ux`, browser automation/inspection is required.
Do not rely on screenshot-only iteration when layout, DOM state, resize behavior,
or graph rendering need verification.

Preferred order:

- Use configured browser MCP first.
- If browser MCP is unavailable, install and use Playwright locally.
- Screenshots are a fallback only, not the primary workflow.

Current local browser MCP:

- `chrome-devtools` is already configured in `~/.codex/config.toml`.
- This should be the default tool for DOM inspection, layout debugging, console
errors, network checks, and viewport validation.

Playwright install fallback:

```bash
cd /home/diego/github/void-control/web/void-control-ux
npm install -D playwright
npx playwright install chromium
```

If Playwright MCP is later added, prefer that over manual screenshots for UI
inspection. No dedicated local skill currently exists in this repo for
Playwright setup; use browser MCP or direct Playwright commands.

## Coding Style & Naming Conventions
For documentation and future code contributions:

- Use clear, boundary-focused naming aligned with the spec (`Run`, `Stage`, `Attempt`, `Runtime`, `Controller`).
- Keep Markdown headings hierarchical and concise.
- Prefer short sections and bullet lists over long prose blocks.
- Use ASCII unless a symbol is required for technical clarity.

## Testing Guidelines
- Keep contract tests in module `#[cfg(test)]` blocks close to conversion/runtime logic.
- Add fixture-based tests for compatibility behavior under `--features serde`.
- Validate both paths before PRs:
- `cargo test`
- `cargo test --features serde`

## Commit & Pull Request Guidelines
Git history is minimal (`Initial commit`), so adopt a consistent imperative style now:

- Commit format: `area: concise action` (example: `spec: clarify cancellation semantics`).
- Keep commits focused to one concern.
- PRs should include:
- A short problem statement.
- A summary of what changed.
- Any spec sections affected (file paths + headings).
- Follow-up work, if intentionally deferred.
Loading
Loading