Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
40c1937
Add draft CLI goals doc for review
claude Sep 25, 2026
b566889
Cut goals doc down to high-level goals
claude Sep 25, 2026
54d289c
Port the Delphi CLI to Rust (parity with bash)
claude Sep 25, 2026
457e9f6
Add v2 design (mapped workspaces) and align goals
claude Sep 26, 2026
c88abc9
Implement v2 mapped workspaces in the Rust CLI
claude Sep 26, 2026
d90b760
Fix review findings; allow file dests inside synced directories
claude Sep 26, 2026
316f878
Simplify the v2 CLI
claude Sep 26, 2026
11c6fe8
Add v2 flow diagram (draw.io source + PNG)
claude Sep 26, 2026
8bb7be3
Design v3: workspaces live in Delphi as materialized folders
claude Sep 26, 2026
cab8262
Add v3 flow diagram (draw.io source + PNG)
claude Sep 26, 2026
e6df74d
Implement v3: workspaces live in Delphi
claude Sep 26, 2026
05e166f
Fix v3 review findings
claude Sep 26, 2026
2bd97ca
Simplify the v3 CLI and refresh docs
claude Sep 26, 2026
28550f7
Keep argos-dev's shared sources in the Argos scope for now
claude Sep 26, 2026
ecacb4b
Use the v1 manifest key names in workspace.yml
claude Sep 26, 2026
3605892
Compose skills from blocks with skill.yml
claude Sep 26, 2026
29ac666
Design v5: workspace as branch root (git subtree projection)
claude Sep 27, 2026
3feb562
Implement v5: workspace as branch root
claude Sep 27, 2026
66edd22
argos-dev: describe the branch-root workflow in CLAUDE.md
claude Sep 27, 2026
d9794fc
v5: shell scripts + subtree merges, org folders under software/
claude Sep 27, 2026
8b0d369
sync.sh: optional refresh|propose direction; propose/<name> branches
claude Sep 27, 2026
1454266
Clean up v5: refresh/propose naming, CI on ws branches, fixes
claude Sep 27, 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
27 changes: 0 additions & 27 deletions .claude/skills/delphi-new-layout/SKILL.md

This file was deleted.

30 changes: 0 additions & 30 deletions .claude/skills/delphi-propose/SKILL.md

This file was deleted.

3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Reviewers for each org folder under software/.
# TODO: replace the placeholder with the real Argos owners (GitHub users or @org/team).
software/application-software/argos/ @argos-owners-placeholder
40 changes: 40 additions & 0 deletions .github/workflows/delphi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Delphi CI (docs/design.md). This file is at main's root and, identically, at the root of every
# ws/<name> (GitHub runs a push's workflow from the pushed commit, so ws pushes need their own copy).
# PRs to main: ci/check.sh. Pushes to main or ws/**: ci/sync.sh (refresh + propose), always run from
# main. Pushes and PRs made with GITHUB_TOKEN trigger no workflows: no loops, and CI-opened PRs
# don't run `check` (sync.sh runs it itself).
name: delphi
on:
pull_request:
branches: [main]
push:
branches: [main, 'ws/**']
permissions:
contents: read
jobs:
check:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- run: ci/check.sh
sync:
if: github.event_name == 'push'
runs-on: ubuntu-latest
concurrency: delphi-sync
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
- env:
GH_TOKEN: ${{ github.token }}
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com'
ci/sync.sh
56 changes: 24 additions & 32 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,31 @@
# Delphi — developing the CLI
# Delphi — developing it

Delphi stores NER's AI-harness context under `context/` and ships a small bash CLI that compiles
layouts into workspaces, refreshes them, and proposes edits back as PRs. The design spec
(`context/docs/delphi-design.md`) is the source of truth.
Delphi stores NER's AI-harness context. Each workspace is a folder `software/**/workspaces/<name>/`
on `main`; branch `ws/<name>` has that folder as its repo root. `ci/sync.sh` keeps them in sync with
subtree merges: **refresh** (main → `ws/<name>`) and **propose** (`ws/<name>` → PR to main via
`propose/<name>`). There is no CLI, just a few shell scripts run by CI. `docs/design.md` is the
source of truth; `docs/goals.md` lists what any change must keep.

## Layout

- `bin/delphi`: dispatcher. It resolves its own path and sources `lib/core.sh`, then the group's module.
- `lib/core.sh`: messages, `defer` cleanup, prompts, config, `safe_path`, Delphi git access, moves, `parse_args`.
- `lib/parse.sh`: YAML-subset parser (POSIX awk).
- `lib/compile.sh`: layout → files (instructions, blocks, docs, skills, MCP, settings) + `.delphi/lock.tsv`.
- `lib/route.sh` + `lib/route.awk`: pending diff + lock → plan → edits in a PR worktree.
- `lib/pr.sh`: the only write path to Delphi (temp worktree, commit with trailers, push, `gh`).
- `lib/provenance.sh`: harness/model/effort resolution.
- `lib/workspace.sh`, `lib/layout.sh`, `lib/block.sh`, `lib/check.sh`, `lib/setup.sh`: the command groups.
- `lib/harness/<name>.sh`: harness adapters (names + `harness_provenance` + `harness_launch`).
- `dev/sandbox.sh`: throwaway end-to-end playground. It is the only test harness (no automated tests, no CI).
- `.claude/skills/`: LLM workflows that drive the CLI (`delphi-new-layout`, `delphi-propose`).
- `ci/sync.sh [refresh|propose] [<name>]`: refresh and/or propose each workspace (both by default).
Runs on pushes to main and `ws/**`.
- `ci/check.sh [<dir>]`: validates the repo. Runs on PRs to main and on each proposal.
- `tools/new-workspace.sh`: new workspace folder from `templates/workspace/` as a PR.
- `templates/workspace/`: `workspace.yml`, `CLAUDE.md` (`{{name}}`, `{{folder}}`), and the managed
files every workspace carries unchanged: `.delphi/setup.sh`, `.github/workflows/delphi.yml`.
- `software/…/workspaces/<name>/`: the workspaces. Org structure is plain directories.
- `.github/workflows/delphi.yml` (identical to the template's copy), `.github/CODEOWNERS`.
- `tests/e2e.sh`: end-to-end test in a throwaway sandbox (bare origin, stub `gh` logging to `gh.log`).

## Rules

- Must run under macOS `/bin/bash` 3.2. Test with `/bin/bash`, never zsh or a newer bash.
- Tools: POSIX awk (no gawk extensions), git, gh. jq is optional.
- Keep it small: fewest lines that implement the spec, terse functions, a short header per file.
- Bash 3.2 pitfalls:
- Functions that `defer` cleanup (`make_tmp`, `delphi_worktree_at`, `pr_begin`) must not run
inside `$(...)`. They return results in `REPLY`.
- errexit is suspended in conditional contexts (`if f`, `f || x`), so critical commands need an explicit `|| die`.
- A dying function inside `$(...)` needs `|| exit 1` at the call site.
- Empty arrays error under `set -u`. Use newline-separated strings.
- A failing command substitution inside a heredoc does not propagate. Assign it to a variable first.
- Use `sed` rather than `grep -v`, which exits 1 on empty input and breaks under pipefail.
- `"$var…"` (a variable followed by a non-ASCII byte) is parsed as a longer name. Write `${var}…`.
An unbound-variable error under the EXIT trap exits with status **0**.
- Every path from config, flags, lock, or `moves.tsv` goes through `safe_path` before use.
- Never test against real GitHub repos. Use the sandbox:
`eval "$(/bin/bash dev/sandbox.sh /tmp/sb1)"`, then `d <command>`.
The sandbox stubs `gh` (log in `$SB/gh.log`), so `--yes` pushes only to its bare origin.
- Keep it small: fewest lines that implement the design; a short header comment per script.
Prefer deleting to adapting. Runtime tools: bash, git, and `gh` (only to open or update PRs).
- Every script: `#!/usr/bin/env bash`, `set -euo pipefail`, `shellcheck`-clean.
- `.delphi/setup.sh` runs on people's machines: bash 3.2 (macOS) and Git Bash safe. No bash-4
features (associative arrays, `mapfile`, `${x,,}`, `|&`), POSIX awk only.
- Changing a managed file (`setup.sh`, the workflow): update the template, `.github/`, and every
workspace copy in the same PR, or `ci/check.sh` fails.
- `bash tests/e2e.sh` and `ci/check.sh` must pass. Add a test there for every behavior change.
- Never test against real GitHub repos or this checkout's origin; use the sandbox in `tests/e2e.sh`.
96 changes: 67 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,82 @@
# Delphi

NER's AI-harness context (knowledge, instructions, skills, MCP, settings), stored compressed
by org chart under `context/`, plus a small bash CLI:
NER's AI-harness context (instructions, skills, docs, settings), organized by the org chart under
`software/`. A **workspace** is a folder `software/**/workspaces/<name>/` with a `workspace.yml`.
For each one, CI keeps a branch **`ws/<name>`** whose repo root *is* that folder, so people and
agents work on it with plain git. Design: `docs/design.md`. Goals: `docs/goals.md`.

- **compile** a *layout* into a local, git-initialized *workspace* where Claude Code runs,
- **refresh** the workspace when `main` moves,
- **propose** workspace edits back as one PR, routed to the blocks they came from.
## How it works

Design: `context/docs/delphi-design.md`.
```
┌───────────────────────────────┐
│ main │
│ software/…/workspaces/<name>/ │
└───────────────────────────────┘
│ ▲
│ refresh │ merge PR
│ (CI) │ (after check.sh)
▼ │
┌──────────────────┐ ┌──────────────────┐
│ ws/<name> │ │ propose/<name> │
│ root = workspace │─►│ PR to main │
└──────────────────┘ └──────────────────┘
│ ▲ propose (CI)
│ branch │ merge PR
▼ │
┌──────────────────┐
│ your branch │
│ edit · commit │
└──────────────────┘

## Quick start
refresh: main → ws/<name> (folder becomes root)
propose: ws/<name> → main PR (root goes back under folder)
CI runs both on every push to main or ws/**
```

```sh
bin/delphi setup # once: puts `delphi` on PATH (~/.local/bin, or pass a dir)
Both directions are subtree merges (`git merge -Xsubtree=<folder>`) done by `ci/sync.sh`, so the
histories stay joined and edits on either side meet in normal three-way merges.

delphi ws new argos-dev # create the workspace
delphi ws open argos-dev # start Claude Code in it
delphi ws propose # send context edits back as a PR (run inside the workspace)
delphi ws refresh # pull in Delphi updates
## Using a workspace

```sh
git clone -b ws/argos-dev https://github.com/Northeastern-Electric-Racing/Delphi.git argos-dev
cd argos-dev && .delphi/setup.sh # clones workspace.yml's repos into repos/ (git-ignored)
git switch -c my-change # edit, commit, push, open a PR into ws/argos-dev
git fetch origin && git merge origin/ws/argos-dev # update your branch any time
```

Code changes go in `repos/argos` with its own PRs. Context changes (CLAUDE.md, skills, docs) are
committed in the workspace and sent back with `propose`.
After your PR merges into `ws/<name>`, CI proposes it: a PR `ws/<name> → main` from
`propose/<name>`. Merge that with a merge commit or squash, never rebase. Never push to `ws/*` or
`main` directly (protect them). Code changes go in `repos/<name>`, through that repo's own PRs.

## Commands
**Conflicts.** If `main` and `ws/<name>` changed the same lines, CI lists the files and skips that
workspace. Fix it in a PR into `ws/<name>`: on a branch cut from `ws/<name>`, run
`git merge -Xsubtree=<folder> origin/main`, resolve, commit.

## workspace.yml

```yaml
harness: claude-code
repos: # cloned into repos/<name> by .delphi/setup.sh
argos: https://github.com/Northeastern-Electric-Racing/Argos.git
```
delphi layout new <scope> <layout> [--from <file>] create a layout (branch + PR)
delphi layout list list layouts on origin/main
delphi workspace new <layout> [--as <ws>] [--ref <branch>]
delphi workspace open|refresh|propose|status (alias: ws)
delphi block mv <old> <new> move a block (branch + PR)
delphi check validate the repo
delphi setup [dir] put `delphi` on PATH
```

Commands that write to Delphi accept `--model`, `--effort` (provenance) and `--yes`. Without
`--yes`, a non-interactive run fails fast instead of prompting.
The workspace's name is its folder name (unique repo-wide). Every other file in the folder is the
workspace's own, at its normal harness path, except two Delphi manages: `.delphi/setup.sh` and
`.github/workflows/delphi.yml` (copies of the template's).

## New workspace

`tools/new-workspace.sh <org-path under software/> <name>` copies `templates/workspace/` into
`software/<org-path>/workspaces/<name>/` and opens a PR to `main`. Once it merges, CI creates
`ws/<name>`.

## CI (`.github/workflows/delphi.yml`)

- PRs to `main`: `ci/check.sh` validates the repo.
- Pushes to `main` or `ws/**`: `ci/sync.sh` refreshes and proposes every workspace.

## Developing Delphi
Repo settings: allow GitHub Actions to create PRs. Don't make `check` a required status check:
PRs opened by CI don't trigger workflows (sync.sh runs `ci/check.sh` itself before proposing).

Test CLI changes in the sandbox, never against GitHub (see `CLAUDE.md`):
`eval "$(/bin/bash dev/sandbox.sh /tmp/delphi-sb)"`, then `d <command>`.
Developing Delphi: see `CLAUDE.md`; `bash tests/e2e.sh` runs everything in a local sandbox.
48 changes: 0 additions & 48 deletions bin/delphi

This file was deleted.

Loading
Loading