Repo-side rename only (Phases 1-3 of the migration plan); the live box (~/.castle, systemd units, /data/castle, domains) is a separate cutover. - Slug `castle` -> `wildpc`: CLI command, module names (wildpc_core/cli/api), dist names, entry point `wildpc = wildpc_cli.main:main`. - Identifiers: CastleConfig/NATSClient/DirError/MDNS -> Wildpc*. - Env/constants: CASTLE_* -> WILDPC_*; ~/.castle -> ~/.wildpc, castle.yaml -> wildpc.yaml, /data/castle -> /data/wildpc. - Systemd UNIT_PREFIX castle- -> wildpc-; own programs castle-api/gateway/etc. - Display prose "Castle" -> "Wild PC" in docs, agent-guide files, README, frontend. - Package dirs and bootstrap yaml renamed via git mv; lockfiles regenerated; redundant nested uv.lock files dropped (workspace root lock is authoritative). Tests: core 273, cli 47, wildpc-api 120 all pass. Frontend type-checks + builds. Fixed a stale test fixture (secret_env_path kind arg) broken pre-rename.
73 lines
3.5 KiB
Markdown
73 lines
3.5 KiB
Markdown
# Developing Wild PC
|
|
|
|
How to work on **Wild PC's own code** — the CLI, core library, control-plane API,
|
|
and dashboard. For *using* Wild PC to manage software (create/deploy/expose
|
|
programs), see the operator guide in [`AGENTS.md`](../AGENTS.md).
|
|
|
|
## The Wild PC monorepo
|
|
|
|
Wild PC's own programs live in **this git repo** (`source: repo:<name>`) — distinct
|
|
from the programs you manage, which live under `/data/repos/<name>/`:
|
|
|
|
- `cli/` — the `wildpc` CLI (installed via `uv tool install --editable cli/`)
|
|
- `core/` — `wildpc_core`: manifest models, config loader, generators
|
|
- `wildpc-api/` — the FastAPI control-plane service (port 9020)
|
|
- `app/` — the dashboard frontend (React/Vite; program name `wildpc`, served at
|
|
`wildpc.<gateway.domain>`)
|
|
|
|
The root `pyproject.toml` is the **uv workspace** (core, cli, wildpc-api).
|
|
|
|
## Key files
|
|
|
|
- `core/src/wildpc_core/manifest.py` — Pydantic models: `ProgramSpec`,
|
|
`DeploymentSpec` (discriminated union on `manager`), `LaunchSpec`, `AgentSpec`, …
|
|
- `core/src/wildpc_core/config.py` — config loader (`wildpc.yaml` + `programs/` +
|
|
`deployments/` → `WildpcConfig`), the two roots, `source:` resolution
|
|
- `core/src/wildpc_core/generators/` — systemd unit/timer + Caddyfile generation
|
|
- `cli/src/wildpc_cli/` — resource-first CLI commands; `templates/scaffold.py`
|
|
- `wildpc-api/src/wildpc_api/` — routes, health polling, SSE `stream.py`, mesh,
|
|
and the agent terminal UX (`agents.py`, `pty_session.py`, `agent_sessions.py`,
|
|
`agent_registry.py`)
|
|
- `ruff.toml` / `pyrightconfig.json` — shared lint/type config
|
|
|
|
## Commands (all projects use uv)
|
|
|
|
```bash
|
|
uv sync
|
|
uv run pytest tests/ -v
|
|
uv run ruff check . && uv run ruff format .
|
|
uv run pyright <paths>
|
|
```
|
|
|
|
Running `uv sync` from a member subdir trims the shared workspace venv — resync
|
|
from the repo root to restore all members. Code style: **ruff** (100-char lines),
|
|
**pyright**, **pytest** + **pytest-asyncio**; Python **3.13** for services, **3.11+**
|
|
for tools/libraries.
|
|
|
|
## wildpc-api endpoints (port 9020)
|
|
|
|
- Core: `GET /health`, `GET /stream` (SSE: health, service-action, mesh)
|
|
- Converge: `POST /apply` (`{name?, plan?}`) — the one lifecycle endpoint
|
|
- Deployments: `GET /deployments[/{name}]`, `GET /status`
|
|
- Catalog + editing: `GET /programs[/{name}]`, `POST /programs/{name}/{action}`
|
|
(dev verbs only), `PUT|DELETE /programs/{name}`; likewise `/services`, `/jobs`
|
|
- Config: `GET|PUT /`, `POST /config/apply`, `PUT /config/deployments/{name}/enabled`
|
|
- Gateway: `GET /gateway`, `GET /gateway/caddyfile`, `PUT /gateway/config` (making
|
|
routes live is convergence: `POST /apply`)
|
|
- Mesh: `GET /mesh/status`, `GET /nodes[/{hostname}]`
|
|
- Agents (dashboard terminal UX): `GET /agents`, `GET /agents/sessions`,
|
|
`GET /agents/history`, `DELETE /agents/sessions/{id}`, `WS /agents/{name}/session`
|
|
- Service actions: `POST /services/{name}/restart`, `GET /services/{name}/unit`
|
|
|
|
## Infrastructure internals
|
|
|
|
- Generated Caddyfile at `~/.wildpc/artifacts/specs/Caddyfile`; a **plugin Caddy**
|
|
at `/usr/local/bin/caddy` when `tls: acme`.
|
|
- Systemd user units at `~/.config/systemd/user/wildpc-*.service` (+ `.timer`);
|
|
the unit for program `X` is `wildpc-X.service`. Use drop-in `*.service.d/*.conf`
|
|
for extra env `wildpc apply` shouldn't overwrite.
|
|
- The `container` launcher resolves docker via `shutil.which("docker")` (preferred
|
|
over rootless podman on this box).
|
|
- Service data at `$WILDPC_DATA_DIR/<name>/`; secrets at `~/.wildpc/secrets/`
|
|
(mode 700) — never in project directories.
|