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
6 changes: 6 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,9 @@ scripts/*
!scripts/verify_attestation.py
!pyproject.toml
!vanguarstew_agent_files.json

# Private runtime state must never enter a build context (openvang product runtime).
.env
data/
*.sqlite3
private-review-results/
25 changes: 25 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copy to .env. Keep this file and vanguarstew.json free of real credentials.
# Existing shell environment values take priority over entries in .env.

# Runtime safety: the initial service does no network or inference work.
VANGUARSTEW_DRY_RUN=true
VANGUARSTEW_ALLOW_EXTERNAL_INFERENCE=false
VANGUARSTEW_POLL_ENABLED=false
VANGUARSTEW_POLL_SECONDS=300
VANGUARSTEW_MAX_JOBS_PER_CYCLE=1
VANGUARSTEW_HOST=127.0.0.1
VANGUARSTEW_PORT=8080

# GitHub is read-only. Use a least-privilege token or, in a later rollout,
# a GitHub App installation token. This runtime cannot write GitHub comments,
# labels, approvals, closures, merges, or releases.
VANGUARSTEW_GITHUB_TOKEN=
VANGUARSTEW_GITHUB_API_BASE=https://api.github.com

# Managed inference is opt-in. Never place this value in vanguarstew.json.
VANGUARSTEW_MODEL=
VANGUARSTEW_API_BASE=
VANGUARSTEW_API_KEY=

# Optional GitHub webhook HMAC secret. Leave blank to disable the webhook route.
VANGUARSTEW_WEBHOOK_SECRET=
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- run: python -m pip install --upgrade pip pytest pytest-cov
- run: python -m pip install --upgrade pip pytest pytest-cov cryptography
- name: Test (offline) with coverage floor
env:
VANGUARSTEW_OFFLINE: "1"
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@ venv/
.coverage
.coverage.*
htmlcov/
.env
data/
*.sqlite3
private-review-results/
14 changes: 14 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Private self-hosted runtime. No secret is copied into this image.
FROM python:3.12-slim

WORKDIR /app
COPY . /app
RUN pip install --no-cache-dir . \
&& useradd --create-home --uid 10001 vanguarstew \
&& mkdir -p /var/lib/vanguarstew \
&& chown -R vanguarstew:vanguarstew /app /var/lib/vanguarstew

USER vanguarstew
ENV VANGUARSTEW_DATA_DIR=/var/lib/vanguarstew
EXPOSE 8080
CMD ["vanguarstew", "serve", "--config", "/app/vanguarstew.json"]
23 changes: 23 additions & 0 deletions deploy/systemd/vanguarstew.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[Unit]
Description=Vanguarstew private maintainer-assist runtime
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=vanguarstew
Group=vanguarstew
WorkingDirectory=/opt/vanguarstew
EnvironmentFile=/etc/vanguarstew/env
ExecStart=/opt/vanguarstew/.venv/bin/vanguarstew serve --config /etc/vanguarstew/vanguarstew.json
Restart=on-failure
RestartSec=10
UMask=0077
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/lib/vanguarstew

[Install]
WantedBy=multi-user.target
14 changes: 14 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
services:
vanguarstew:
build: .
restart: unless-stopped
env_file:
- .env
volumes:
- ./data:/var/lib/vanguarstew
- ./vanguarstew.json:/app/vanguarstew.json:ro
ports:
- "127.0.0.1:8080:8080"
init: true
security_opt:
- no-new-privileges:true
150 changes: 150 additions & 0 deletions docs/openvang-agent-factory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# OpenVang agent factory

## Product direction

OpenVang is building the owner-level operating system for a Bittensor subnet.
It coordinates specialist agents for validator work, maintainer stewardship,
miner QA, building and running, product planning, QA, scheduling, and
defensive adversarial QA. It is not a monolithic autonomous owner account.

The first factory implementation is policy-only: it makes authority, memory,
and publication boundaries machine-checkable before any chain, wallet, or
repository-write adapter is introduced.

## Roles

| Role | Owns | May not do automatically |
| --- | --- | --- |
| Validator | validation, scoring, receipt verification | change emissions, sign, vote, publish |
| Maintainer | private repository analysis and recommendations | comment, merge, label, close, publish review evidence |
| Miner QA | miner protocol/output conformance | score itself, alter miner state, publish raw traces |
| Builder | isolated builds and bounded runs | deploy or access credentials |
| Product | plans and owner proposals | publish, change roadmap/governance state |
| QA | acceptance and regression evidence | bypass a failing gate |
| Scheduler | dispatch, leases, recovery | grant permissions or perform an owner action |
| Security QA | defensive adversarial testing and remediation proposals | exploit third parties, disclose findings, mutate production |

“Exploit agent” is therefore implemented as **security QA**: it performs
authorized, defensive attack simulation in isolated environments and proposes
containment. It does not receive an offensive execution capability.

## Owner boundary

The factory has no automatic capability for:

- wallet/key access or signing;
- Bittensor transactions, emissions changes, or governance votes;
- GitHub writes: comments, labels, reviews, closes, merges, releases, or
permission changes; and
- public communication or publication.

An agent can prepare a commitment-bound `ActionIntent` for such work. The
intent contains digests of the payload and rationale, not an execution handle.
`FactoryPolicy.can_auto_execute(...)` is always false. A later owner-action
adapter requires its own proposal, signer separation, explicit approval,
idempotency design, audit policy, and rollback/containment plan.

## Memory contract

Every memory item has both a role scope and an artifact class.

| Scope | Intended use | Cross-role transfer |
| --- | --- | --- |
| `role-private` | raw private operational material | never |
| `shared-commitment` | bounded, shaped coordination facts | commitment-only |
| `publishable-commitment` | externally verifiable public-safe fact | commitment-only |

Private maintainer review material remains `role-private`. It cannot cross into
another role, an HTTP response, a benchmark artifact, a Polaris receipt, a
GitHub comment, or public status. A validator may create a narrow public-safe
commitment, but the policy does not give it publication authority.

`openvang/memory.py` makes the role boundary durable for factory work. A
`FactoryMemoryVault` accepts role-private JSON only through an
operator-supplied authenticated cipher, binds ciphertext to the record id,
role, and plaintext commitment, and keeps an append-only owner-only SQLite
store. Reading requires the same role; a wrong key, altered ciphertext, or
altered binding fails closed. The default package does not invent or persist a
key: deployments using the local Fernet implementation install
`vanguarstew[private-memory]` and supply their key through a secret manager or
other operator-controlled channel.

Cross-role memory in this vault accepts only an already-shaped SHA-256
commitment. It has no API to derive a shared fact from a private record. This
prevents private reviewer material—including its existence, content, reasoning,
or source trace—from being promoted into another role's memory or any public
surface.

This builds on the existing Vanguarstew memory rule: live and benchmark memory
remain separate, benchmark views are time-safe, and raw memory is excluded from
attestation evidence.

## Initial implementation

`openvang/factory.py` declares all eight role contracts and checks:

1. every role has a least-privilege action set;
2. no role can gain an owner-level action;
3. only the validator can create a publishable memory commitment;
4. cross-role exchange excludes role-private artifacts; and
5. public shapes are commitment-only and no role can publish them directly.

It deliberately has no Bittensor SDK, signer, wallet, GitHub-write client,
public webhook, or remote execution dependency.

`openvang/scheduler.py` is the first private control-plane primitive. It stores
only opaque task/output commitments, target role, allowed action, output scope,
budget units, status, and a bounded worker lease in an owner-only SQLite file.
It cannot execute work or expose a task through a network interface.

`openvang/isolated.py` is the first non-privileged adapter. It accepts only a
live leased `run-isolated` task for miner QA, builder, QA, or security QA. Its
input commitment, the owner-supplied approval digest, and an exact
`SealedExecutionPlan` must all match. It delegates only to the existing sealed
executor with its fixed resource and network boundary, independently checks the
aggregate-only result contract, and writes just an output digest back to the
scheduler. It has no shell-command interface, remote executor, credential
access, GitHub client, public output, or cross-role-memory access.

The adapter is deliberately local and operator-invoked for now. A worker must
claim a lease that covers the approved execution time; a stale or hand-built
task is rejected before the sealed executor starts. Its result receipt is a
local commitment, not a Polaris receipt, publication, or proof of workload
confidentiality.

`openvang/subnet.py` provides the next adapter boundary without embedding a
Bittensor client. It accepts an injected, separately reviewed read-only source
and a fixed `subnet-state-v1` projection: network, netuid, block height, and
participant/validator counts. The source cannot return hotkeys, wallet data,
endpoints, weights, prompts, or arbitrary fields through this adapter. A live
validator, miner-QA, or product task is bound to the exact request commitment;
only the normalized snapshot digest is retained. The operator remains
responsible for the source endpoint, credentials (if any), and independently
enforcing that it has no write capability.

Inspect the static contract locally:

```bash
vanguarstew factory-policy
```

This command is informational only. It does not load runtime configuration or
secrets, inspect memory, contact a subnet, or authorize an action.

## Rollout sequence

1. Run the policy registry and commitment-only scheduler beside the current
Vanguarstew runtime in dry-run mode and record only aggregate
authorization-denial telemetry locally.
2. Attach one non-privileged adapter at a time: local isolated build/QA and a
strict read-only subnet-state boundary are available; a live Bittensor
source still requires separate deployment review. A worker claims only work
assigned to its role.
3. Pilot one subnet with a fixed budget and an independent validator/QA check.
4. Only after an operator workflow and threat model are approved, consider a
narrowly scoped owner-action adapter. It must use external signing and a
human approval step; no general owner key enters the factory.

The existing 24/7 Vanguarstew runtime remains a private maintainer-assist
component within this architecture. It is not promoted to a subnet-wide owner
agent by this policy scaffold.
121 changes: 121 additions & 0 deletions docs/product-runtime-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Product runtime plan

## Goal

Turn Vanguarstew from an operator-run development tool into a self-hosted
maintainer-assist service that survives restarts, is straightforward to deploy,
and preserves the project's strict private-review boundary. The product keeps
the existing `solve(...)` contract and benchmark/TEE systems separate from
live operations.

The first deliverable is a private control plane. It accepts work, stores
private results locally, and exposes only loopback health checks. It does not
post a review, merge, label, close, reopen, or otherwise mutate GitHub.

## Security and publication contract

| Data | Runtime handling | Public output |
| --- | --- | --- |
| GitHub token, webhook secret, model key | environment only; never JSON config, logs, or status | never |
| PR diff, model prompt, review result, private review evidence | owner-only local result directory | never |
| Runtime queue and heartbeat | owner-local SQLite | never |
| `/healthz`, `/readyz` | loopback-only operational endpoints | static health state only |
| Benchmark / Polaris TEE evidence | independent benchmark pipeline | existing receipt-safe commitments only |

Live review data must never be copied into benchmark artifacts, Polaris receipts,
leaderboards, GitHub comments, or the runtime HTTP response. A public result
requires a separate, explicit publication design and review; it is outside this
runtime plan.

## Delivery phases

1. **Private local foundation — implemented now.** `vanguarstew init`,
`doctor`, `run-once`, and `serve`; env-only secrets; durable SQLite work
queue; owner-only review files; read-only GitHub client; signed webhook
intake; loopback health probes; Compose and systemd templates.
2. **Controlled live pilot.** Configure one repository and a least-privilege
GitHub App/read token. Enable inference explicitly, keep outputs local, and
observe cost, queue latency, retries, and failure classes. No automatic
GitHub write action.
3. **Operator workflow.** Add an authenticated private operator console or
explicit command for a maintainer to inspect and selectively publish a
bounded, policy-approved summary. This must not reveal private reviewer
purpose, evidence, or reasoning traces.
4. **Scale and recovery.** Move queue ownership to a managed database only if
the local SQLite deployment has demonstrated a real capacity limit; add
encrypted backup/restore drills, metrics with aggregate-only telemetry, and
key rotation.
5. **Optional automation.** Any GitHub write capability needs a separate
threat model, GitHub App permission review, idempotency contract, audit
controls, and an explicit maintainer approval gate. It is not enabled by
this implementation.

## Operator flow

```bash
cp .env.example .env
cp vanguarstew.json.example vanguarstew.json
python -m pip install -e .
vanguarstew doctor
vanguarstew serve
```

The copied configuration is intentionally inert: dry-run mode is on and polling
is off. `doctor` makes the state visible without making a network request and
without printing any secret. For a controlled pilot, the operator must make all
three conscious changes in `.env`:

```dotenv
VANGUARSTEW_DRY_RUN=false
VANGUARSTEW_ALLOW_EXTERNAL_INFERENCE=true
VANGUARSTEW_POLL_ENABLED=true
```

They must also provide `VANGUARSTEW_GITHUB_TOKEN`, `VANGUARSTEW_MODEL`,
`VANGUARSTEW_API_BASE`, and `VANGUARSTEW_API_KEY`. The GitHub integration is
read-only; completing a local review still causes no GitHub mutation.

For a service manager, use either `docker compose up -d` (the port remains
bound to `127.0.0.1`) or adapt `deploy/systemd/vanguarstew.service`. Keep the
data directory, `.env`, configuration, and journal private to the operator.

## Operational checks

- `vanguarstew doctor` must pass before starting the service.
- `curl http://127.0.0.1:8080/healthz` and `/readyz` are the only intended
unauthenticated monitoring probes. Neither identifies a repository, PR, or
review outcome.
- Inspect `data/private-review-results/` only on the host; it is deliberately
not an API route.
- Keep `VANGUARSTEW_DRY_RUN=true` for installation and upgrades. Explicitly
enable live inference only after validating the selected model provider's
data-handling terms and spend limit.
- The queue uses delivery/head identifiers to make repeated webhook delivery or
poll cycles harmless. Failed work remains locally visible as a failure class,
not as a published review trace.
- Work deferred by dry-run or disabled inference returns to the queue only when
the operator explicitly enables live private inference. A crashed in-progress
claim is retried only after its 15-minute lease expires; hard failures are not
retried automatically.

## Acceptance gates for the first live pilot

1. A fresh host can complete the operator flow from an empty data directory.
2. Restarting the process retains queued and completed state without duplicating
a delivery.
3. A valid signed webhook queues at most one review; an invalid signature
exposes no payload and creates no work.
4. A dry run produces no network requests and no inference invocation.
5. No endpoint, log line, benchmark artifact, or GitHub action exposes review
content or creates a GitHub mutation.
6. A local review result is owner-readable only, and the service still exposes
only health/readiness status.

## Non-goals for this phase

- Replacing the validator-facing `solve(...)` entrypoint.
- Treating Polaris as a confidentiality layer. Polaris remains an integrity
receipt path for supported benchmark jobs, not a store for live review data.
- Auto-merge, auto-close, auto-label, comment posting, or participant scoring.
- Claiming memory improves live quality before an independently held-out,
preregistered ablation passes its declared gate.
Loading