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
2 changes: 1 addition & 1 deletion .delphi/manifest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# MINOR something new that existing clones need nothing for
# MAJOR clones need cleanup (MINOR while 0.x): add .delphi/migrations/<version>-<slug>.sh, which
# setup.sh runs once per workspace in each clone (rules in Delphi's CLAUDE.md)
version: 1.0.0
version: 1.1.0
files: # repo-relative paths; a trailing / means everything under it
- .delphi/manifest.yml
- .delphi/.gitattributes
Expand Down
2 changes: 1 addition & 1 deletion .delphi/new-worktree.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# .delphi/new-worktree.sh <repo> <branch> [<base>]: create or reuse worktrees/<repo>/<branch> from
# the store .delphi/setup.sh made at repos/<repo>, and print its path. An existing branch
# the clone .delphi/setup.sh made at repos/<repo>, and print its path. An existing branch
# (local or on origin) is checked out; a new one starts from <base> (default: origin's default
# branch). Runs on bash 3.2 and Git Bash.
set -euo pipefail
Expand Down
2 changes: 1 addition & 1 deletion .delphi/paths.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# Bash and zsh safe.
# shellcheck shell=bash
DELPHI_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")/.." && pwd)
DELPHI_REPOS=$DELPHI_ROOT/repos # bare stores: repos/<repo>
DELPHI_REPOS=$DELPHI_ROOT/repos # clones: repos/<repo>
DELPHI_WORKTREES=$DELPHI_ROOT/worktrees # checkouts: worktrees/<repo>/<branch>
DELPHI_REFERENCES=$DELPHI_ROOT/references # read-only dependency sources: references/<name>
DELPHI_WORKSPACES=$DELPHI_ROOT/workspaces # Delphi clones to read: workspaces/<workspace>, workspaces/main
Expand Down
25 changes: 4 additions & 21 deletions .delphi/setup.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#!/usr/bin/env bash
# .delphi/setup.sh: run in a checkout of ws/<name> (the workspace root; .delphi/ comes from Delphi's
# main, which sync keeps on every ws/* branch, so edit it only there; on main this does nothing). For each repo listed under
# `repos:` in workspace.yml, fetches it into a bare store at repos/<name> (unless present) and checks
# out its default branch as the first worktree, worktrees/<name>/<default-branch>. For each repo under
# `repos:` in workspace.yml, clones it at repos/<name> (unless present), on its default branch, and
# adds nothing else (.delphi/new-worktree.sh makes worktrees from it). For each repo under
# `references-git:` (read-only dependency sources, `<name>: <git-url> [<ref>]`), checks out a shallow,
# detached copy of <ref> (default: origin's default branch) at references/<name>, refreshed on every
# run, with pushes disabled. Each entry under `workspaces:` (`- <name>`, a workspace's dotted name
Expand Down Expand Up @@ -99,25 +99,8 @@ while read -r kind name url ref; do
if [ "$kind" = link ]; then [ -n "$inside" ] || link "$name"; continue; fi
case "$name" in . | .. | *[!A-Za-z0-9._-]*) echo "setup: skipping unsafe repo name '$name'" >&2 && continue ;; esac
if [ "$kind" = ref ]; then readonly_copy "references/$name" "$url" ${ref:+"$ref"} && continue; fi
store=repos/$name
if [ -e "$store" ]; then
echo "repos/$name: already present"
else
git init -q --bare "$store"
git -C "$store" remote add origin "$url"
git -C "$store" fetch -q origin </dev/null
git -C "$store" remote set-head origin -a >/dev/null </dev/null
fi
def=$(git -C "$store" symbolic-ref -q --short refs/remotes/origin/HEAD) ||
{ echo "setup: repos/$name has no origin/HEAD; skipping its worktree" >&2 && continue; }
def=${def#origin/}
dest=worktrees/$name/$def
if [ -e "$dest" ]; then continue
elif git -C "$store" rev-parse -q --verify "refs/heads/$def" >/dev/null; then
git -C "$store" worktree add -q "$PWD/$dest" "$def" ||
echo "setup: could not check out $dest (is $def checked out in repos/$name?)" >&2
else
git -C "$store" worktree add -q --track -b "$def" "$PWD/$dest" "origin/$def"
if [ -e "repos/$name" ]; then echo "repos/$name: already present"
else git clone -q "$url" "repos/$name" </dev/null || echo "setup: could not clone $url into repos/$name" >&2
fi
done <<EOF2
$list
Expand Down
1 change: 1 addition & 0 deletions .delphi/versions
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
0.8.0 05d4c954a946 workspaces are named by their folders' short names and leaf, joined by dots (.delphi/names.sh, short-name files; ws/s.app.argos.argos-dev, was ws/software/…/argos-dev); workspaces: entries are - <name> | - main, copied to linked/<name>; sync carries ws/<old> over once (migration)
0.9.0 b850821eaa9a linked/<name> are full clones on ws/<name> (or main) tracking origin, pushes allowed; setup.sh switches each back to its branch if switched away and pulls it (migration)
1.0.0 44693a895995 1.0: workspaces: clones live at workspaces/<name> (was linked/<name>; DELPHI_WORKSPACES, was DELPHI_LINKED); setup.sh also runs each one's own setup.sh, and a workspace inside another's workspaces/ skips its own workspaces: (migration)
1.1.0 a3446f7f763c setup.sh clones each repos: entry at repos/<name> (a normal clone on its default branch, was a bare store) and adds no worktree; new-worktree.sh makes worktrees from that clone; older bare stores are left as they are
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ histories stay joined and edits on either side meet in normal three-way merges.

```sh
git clone -b ws/s.app.argos.argos-dev https://github.com/Northeastern-Electric-Racing/Delphi.git delphi
cd delphi && .delphi/setup.sh # repos/ stores + default-branch worktrees in worktrees/ (git-ignored)
cd delphi && .delphi/setup.sh # clones repos: into repos/ (git-ignored)
.delphi/switch.sh s.app.nero.nero-experimental # switch freely (or to main; --list lists them): the hook parks them (and workspace.yml's park: folders) in .delphi/parked/
claude plugin install delphi@delphi --scope user # then /ws-delphi in Claude Code: a pane to keep open that switches workspaces (/ws-delphi --web: in a browser)
git switch -c my-change # edit, commit, push, open a PR into ws/s.app.argos.argos-dev
Expand All @@ -53,7 +53,7 @@ git fetch origin && git merge origin/ws/s.app.argos.argos-dev # update your br
After your PR merges into `ws/<name>`, CI proposes it: a PR `ws/<name> → main` from
`propose/<name>`, labelled `by: ai` (change the label if you wrote it; CI keeps it). Merge that with a
merge commit or squash, never rebase. Never push to `ws/*` or
`main` directly (protect them). Code changes go in a worktree, `worktrees/<repo>/<branch>` (`.delphi/new-worktree.sh`), through that repo's own PRs.
`main` directly (protect them). Code changes go in the clone at `repos/<repo>` (one thing at a time) or a worktree from it, `worktrees/<repo>/<branch>` (`.delphi/new-worktree.sh`), through that repo's own PRs.

**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
Expand All @@ -64,7 +64,7 @@ workspace. Fix it in a PR into `ws/<name>`: on a branch cut from `ws/<name>`, ru
```yaml
name: s.app.argos.argos-dev # its dotted name
harness: claude-code
repos: # stored in repos/<name>, checked out in worktrees/<name>/ by .delphi/setup.sh
repos: # cloned at repos/<name>/ by .delphi/setup.sh; worktrees from it in worktrees/<name>/
argos: https://github.com/Northeastern-Electric-Racing/Argos.git
references-git: # read-only dependency sources, shallow-cloned into references/<name>/
socketioxide: https://github.com/Totodore/socketioxide.git v0.18.7 # optional tag or branch
Expand All @@ -74,7 +74,7 @@ workspaces: # Delphi workspaces (by name) or main, cloned into works

`repos:` are the code you change. `references-git:` are open-source dependencies the agent reads for
context: `setup.sh` checks each out shallow and detached at its pin (or the default branch), with
pushes disabled, and refreshes them on every run. They get no store and no worktrees. Names are
pushes disabled, and refreshes them on every run. They get no clone in `repos/` and no worktrees. Names are
unique across both maps. The `-git` suffix leaves room for other kinds of references later.
`workspaces:` are other workspaces (`- <name>`) or `main` to read: full clones of Delphi itself, each on
its branch (`ws/<name>` or `main`) tracking origin, so `git status` and `git log` work as usual. Every
Expand Down
12 changes: 6 additions & 6 deletions docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,14 +196,14 @@ Nobody pushes to `ws/*` or `main` directly (branch protection; CI's token is the

## 5. `.delphi/setup.sh` (on every branch; does nothing on main, which has no `workspace.yml`)

First runs the workspace's pending migrations (section 5b). Then reads `repos:` from `workspace.yml` and, for each not yet present, fetches it into a bare store at
`repos/<name>`, then checks out its default branch as the first worktree,
`worktrees/<name>/<default-branch>/` (re-created if missing). Adds the folders `park.sh` parks
First runs the workspace's pending migrations (section 5b). Then reads `repos:` from `workspace.yml` and, for each not yet present, clones it at
`repos/<name>/` on its default branch, for people working on one thing at a time, and adds nothing
else (an older clone's bare store there is left as it is). Adds the folders `park.sh` parks
and `.DS_Store` to the clone's `.git/info/exclude` once. For each repo under `references-git:` (read-only dependency
sources), it fetches `<ref>` (default: origin's `HEAD`) with `--depth 1` into `references/<name>/`,
checks it out detached, disables pushes, and does this again on every run, so the copy tracks its pin;
a failed fetch is reported and the old copy kept. Adds `/references/` to the exclude too; references get
no store and no worktrees (`new-worktree.sh` refuses them). Each entry under `workspaces:` (`- <name>`
no clone in `repos/` and no worktrees (`new-worktree.sh` refuses them). Each entry under `workspaces:` (`- <name>`
or `- main`; the workspace itself is skipped) gets a full clone of the clone's own origin at
`workspaces/<name>/`, on that branch (`ws/<name>` or `main`) tracking origin, so it behaves as a normal
checkout (`git status` shows its branch). Every run switches it back to that branch if it was switched
Expand All @@ -218,7 +218,7 @@ and each copy parks with its workspace. Writes the clone's `post-checkout` hook,
runs `.delphi/park.sh` from the worktree that checked out (replacing an older link to or copy of a
`park.sh`), unless another hook is there (it says so and leaves it). `.delphi/` is on every branch, so
the hook always runs the `park.sh` just checked out, never a stale copy, and each worktree of the clone
its own: the worktrees share one hook, so a link would run one checkout's `park.sh` for all of them. Nothing else: code is edited only in worktrees. Must run on macOS `/bin/bash` 3.2
its own: the worktrees share one hook, so a link would run one checkout's `park.sh` for all of them. Nothing else. Must run on macOS `/bin/bash` 3.2
and Git Bash: no bash-4 features, POSIX awk only.

`.delphi/park.sh` (the hook) lets one clone switch freely between workspaces and `main`. When a
Expand All @@ -236,7 +236,7 @@ out; nothing is repaired or rebuilt. Branches of the same workspace move nothing
overwrites: a folder in the way is reported and the other copy stays parked.

`.delphi/new-worktree.sh <repo> <branch> [<base>]` creates or reuses `worktrees/<repo>/<branch>`
from that store: checks out an existing branch, else starts one from `<base>` (default `origin/HEAD`). Same shell rules.
from the clone at `repos/<repo>`: checks out an existing branch, else starts one from `<base>` (default `origin/HEAD`). Same shell rules.
The inherited `new-worktree` skill makes worktrees the default way to start a branch.

`.delphi/paths.sh` is the layout in one place: sourced, it sets and exports `DELPHI_ROOT` (from the
Expand Down
2 changes: 1 addition & 1 deletion docs/goals.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ anyone, person or agent, work on a workspace with plain git and send improvement
- **G1. Workspaces live in Delphi.** Each workspace is a folder on `main` with every file at its
normal harness location.
- **G2. The workspace is the repo root.** Checking out `ws/<name>` gives exactly that workspace at
the root. `.delphi/setup.sh` checks out the code repos it lists as worktrees.
the root. `.delphi/setup.sh` clones the code repos it lists.
- **G3. Both directions, automatically.** Refresh: changes on `main` reach `ws/<name>`. Propose:
merged workspace changes reach `main` as a PR.
- **G4. Conflicts are reported, never guessed.** A conflicting workspace is skipped with its files
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ park: # `- <folder>`: root folders that park with this works
- .playwright-mcp
- .playwright-cli
# .delphi/setup.sh checks out everything below (git-ignored); re-run it after any change.
repos: # `<name>: <git-url>`: code you change; bare store at repos/<name>, default branch at worktrees/<name>/<branch>
repos: # `<name>: <git-url>`: code you change; a clone at repos/<name> (worktrees from it: worktrees/<name>/<branch>)
argos: https://github.com/Northeastern-Electric-Racing/Argos.git
odyssey-definitions: https://github.com/Northeastern-Electric-Racing/Odyssey-Definitions.git # CAN definitions for verify-telemetry
workspaces: # `- <name>` (dotted) or `- main`: Delphi workspaces to read, not edit from here; a clone on its branch at workspaces/<name or main>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Delphi workspace

You're in Delphi workspace `s.app.argos.argos-dev` (branch `ws/s.app.argos.argos-dev`); code repos are checked out as worktrees under `worktrees/<repo>/` (`.delphi/setup.sh` makes the default branch's). Make new branches as worktrees (`new-worktree` skill) unless the user says not to. Delphi workspaces (or `main`) under `workspaces:` in `workspace.yml` (`- <name>`, a workspace's dotted name like `s.app.argos.argos-dev`, or `- main`) are clones at `workspaces/<name>/`, each on its branch, for reading their context (don't edit them from here; setup switches each back to its branch and pulls it); change what's checked out with the `setup-workspace` skill. To work in another workspace, switch this clone to it (`switch-workspace` skill). Park rough notes with the `journal` skill. Work here unless the task clearly belongs to another project.
You're in Delphi workspace `s.app.argos.argos-dev` (branch `ws/s.app.argos.argos-dev`); code repos are cloned at `repos/<repo>/` (`.delphi/setup.sh`), for people working on one thing at a time; leave those clones alone and make new branches as worktrees under `worktrees/<repo>/<branch>` (`new-worktree` skill) unless the user says not to. Delphi workspaces (or `main`) under `workspaces:` in `workspace.yml` (`- <name>`, a workspace's dotted name like `s.app.argos.argos-dev`, or `- main`) are clones at `workspaces/<name>/`, each on its branch, for reading their context (don't edit them from here; setup switches each back to its branch and pulls it); change what's checked out with the `setup-workspace` skill. To work in another workspace, switch this clone to it (`switch-workspace` skill). Park rough notes with the `journal` skill. Work here unless the task clearly belongs to another project.

Always work from the workspace root (this clone's top, where `workspace.yml` is); the layout exists so one session can reach every worktree from there. Name worktrees by path: `git -C worktrees/argos/<branch> …` runs git there without moving, and a one-off subshell like `(cd worktrees/argos/<branch>/angular-client && npx ng lint)` runs anything else. If you `cd` into a worktree to look closely at something, `cd` back to the root as soon as you're done. Skill scripts take only names (repo, branch) and find the rest from `$DELPHI_ROOT`, which a session hook sets in every shell (`$DELPHI_WORKTREES` and the other `.delphi/paths.sh` folders too).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ park: # `- <folder>`: root folders that park with this works
- .playwright-mcp
- .playwright-cli
# .delphi/setup.sh checks out everything below (git-ignored); re-run it after any change.
repos: # `<name>: <git-url>`: code you change; bare store at repos/<name>, default branch at worktrees/<name>/<branch>
repos: # `<name>: <git-url>`: code you change; a clone at repos/<name> (worktrees from it: worktrees/<name>/<branch>)
argos: https://github.com/Northeastern-Electric-Racing/Argos.git
odyssey-definitions: https://github.com/Northeastern-Electric-Racing/Odyssey-Definitions.git
references-git: # `<name>: <git-url> [<tag-or-branch>]`: dependency sources to read, never edit; shallow copy at references/<name>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Delphi workspace

You're in Delphi workspace `s.app.argos.experimental` (branch `ws/s.app.argos.experimental`); code repos are checked out as worktrees under `worktrees/<repo>/` (`.delphi/setup.sh` makes the default branch's). Make new branches as worktrees (`new-worktree` skill) unless the user says not to. Delphi workspaces (or `main`) under `workspaces:` in `workspace.yml` (`- <name>`, a workspace's dotted name like `s.app.argos.argos-dev`, or `- main`) are clones at `workspaces/<name>/`, each on its branch, for reading their context (don't edit them from here; setup switches each back to its branch and pulls it); change what's checked out with the `setup-workspace` skill. To work in another workspace, switch this clone to it (`switch-workspace` skill). Park rough notes with the `journal` skill. Work here unless the task clearly belongs to another project.
You're in Delphi workspace `s.app.argos.experimental` (branch `ws/s.app.argos.experimental`); code repos are cloned at `repos/<repo>/` (`.delphi/setup.sh`), for people working on one thing at a time; leave those clones alone and make new branches as worktrees under `worktrees/<repo>/<branch>` (`new-worktree` skill) unless the user says not to. Delphi workspaces (or `main`) under `workspaces:` in `workspace.yml` (`- <name>`, a workspace's dotted name like `s.app.argos.argos-dev`, or `- main`) are clones at `workspaces/<name>/`, each on its branch, for reading their context (don't edit them from here; setup switches each back to its branch and pulls it); change what's checked out with the `setup-workspace` skill. To work in another workspace, switch this clone to it (`switch-workspace` skill). Park rough notes with the `journal` skill. Work here unless the task clearly belongs to another project.

# NER Software conventions

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ park: # `- <folder>`: root folders that park with this works
- .playwright-mcp
- .playwright-cli
# .delphi/setup.sh checks out everything below (git-ignored); re-run it after any change.
repos: # `<name>: <git-url>`: code you change; bare store at repos/<name>, default branch at worktrees/<name>/<branch>
repos: # `<name>: <git-url>`: code you change; a clone at repos/<name> (worktrees from it: worktrees/<name>/<branch>)
argos: https://github.com/Northeastern-Electric-Racing/Argos.git
odyssey-definitions: https://github.com/Northeastern-Electric-Racing/Odyssey-Definitions.git
workspaces: # `- <name>` (dotted) or `- main`: Delphi workspaces to read, not edit from here; a clone on its branch at workspaces/<name or main>
Expand Down
Loading
Loading