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.1.0
version: 1.2.0
files: # repo-relative paths; a trailing / means everything under it
- .delphi/manifest.yml
- .delphi/.gitattributes
Expand Down
13 changes: 7 additions & 6 deletions .delphi/new-worktree.sh
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
#!/usr/bin/env bash
# .delphi/new-worktree.sh <repo> <branch> [<base>]: create or reuse worktrees/<repo>/<branch> from
# 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.
# the bare store .delphi/setup.sh made at worktrees/<repo>/.bare (never the clone 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
# shellcheck source-path=SCRIPTDIR source=paths.sh
. "$(dirname "$0")/paths.sh"
repo=${1:?usage: new-worktree.sh <repo> <branch> [<base>]} branch=${2:?usage: new-worktree.sh <repo> <branch> [<base>]}
base=${3:-origin/HEAD} dest="$DELPHI_WORKTREES/$repo/$branch"
g() { git -C "$DELPHI_REPOS/$repo" "$@"; }
[ -d "$DELPHI_REPOS/$repo" ] ||
{ echo "new-worktree: no repos/$repo (list it under repos: and run .delphi/setup.sh; references are read-only)" >&2 && exit 1; }
store=$DELPHI_WORKTREES/$repo/.bare
g() { git -C "$store" "$@"; }
[ -d "$store" ] ||
{ echo "new-worktree: no worktrees/$repo/.bare (list it under repos: and run .delphi/setup.sh; references are read-only)" >&2 && exit 1; }
g fetch -q origin
if [ -d "$dest" ]; then :
elif g rev-parse -q --verify "refs/heads/$branch" >/dev/null; then
Expand Down
2 changes: 1 addition & 1 deletion .delphi/paths.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# shellcheck shell=bash
DELPHI_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")/.." && pwd)
DELPHI_REPOS=$DELPHI_ROOT/repos # clones: repos/<repo>
DELPHI_WORKTREES=$DELPHI_ROOT/worktrees # checkouts: worktrees/<repo>/<branch>
DELPHI_WORKTREES=$DELPHI_ROOT/worktrees # checkouts: worktrees/<repo>/<branch>, from the bare store worktrees/<repo>/.bare
DELPHI_REFERENCES=$DELPHI_ROOT/references # read-only dependency sources: references/<name>
DELPHI_WORKSPACES=$DELPHI_ROOT/workspaces # Delphi clones to read: workspaces/<workspace>, workspaces/main
export DELPHI_ROOT DELPHI_REPOS DELPHI_WORKTREES DELPHI_REFERENCES DELPHI_WORKSPACES
Expand Down
23 changes: 21 additions & 2 deletions .delphi/setup.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#!/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, 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
# `repos:` in workspace.yml, clones it at repos/<name> (unless present). Separately, fetches it into a
# bare store at worktrees/<name>/.bare (unless present) and checks out its default branch as the first
# worktree, worktrees/<name>/<default-branch> (re-created if missing); .delphi/new-worktree.sh makes the
# others from that store, so worktrees never touch the clone. 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 @@ -102,6 +104,23 @@ while read -r kind name url ref; do
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
store=worktrees/$name/.bare
if [ ! -e "$store" ]; then
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: $store 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" >&2
else
git -C "$store" worktree add -q --track -b "$def" "$PWD/$dest" "origin/$def"
fi
done <<EOF2
$list
EOF2
Expand Down
1 change: 1 addition & 0 deletions .delphi/versions
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
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
1.2.0 d139aaf9f4a5 worktrees come from their own bare store, worktrees/<name>/.bare, separate from the plain clone at repos/<name>; setup.sh makes the store and the default-branch worktree again; an older bare store at repos/<name> is left as it is
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 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.
`main` directly (protect them). Code changes go in a worktree, `worktrees/<repo>/<branch>` (`.delphi/new-worktree.sh`, from its own store at `worktrees/<repo>/.bare`, separate from the clone at `repos/<repo>`), 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: # cloned at repos/<name>/ by .delphi/setup.sh; worktrees from it in worktrees/<name>/
repos: # cloned at repos/<name>/; separately, worktrees (default branch first) at worktrees/<name>/<branch>/
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 Down
9 changes: 6 additions & 3 deletions docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,11 @@ 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, 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
`repos/<name>/`, a plain clone of its own. Separately, it fetches the repo into a bare store at
`worktrees/<name>/.bare/` and checks out its default branch as the first worktree,
`worktrees/<name>/<default-branch>/` (re-created if missing), so it's there to see and branch from.
Worktrees come only from that store, so they never touch the clone (a branch can be checked out once
per repository, and the two are separate repositories). 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;
Expand Down Expand Up @@ -236,7 +239,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 the clone at `repos/<repo>`: checks out an existing branch, else starts one from `<base>` (default `origin/HEAD`). Same shell rules.
from the store at `worktrees/<repo>/.bare`: 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` clones the code repos it lists.
the root. `.delphi/setup.sh` clones the code repos it lists and, separately, checks out their default branch as a worktree.
- **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; a clone at repos/<name> (worktrees from it: worktrees/<name>/<branch>)
repos: # `<name>: <git-url>`: code you change; a clone at repos/<name>, and separately worktrees/<name>/<branch> (default branch first)
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
Expand Up @@ -19,7 +19,7 @@ while IFS=$'\t' read -r name link; do
awk '/##\[group\]Run / { step = $0; n = 0; next } /##\[error\]/ { print step; for (i = 0; i < n; i++) print m[i]; print; exit }
tolower($0) ~ /error|fail|panick/ && $0 !~ /^npm error *$/ && n < 10 { m[n++] = $0 }' | cut -c1-200
done <<<"$jobs"
g() { git -C "$DELPHI_REPOS/argos" "$@"; }
g() { git -C "$DELPHI_WORKTREES/argos/.bare" "$@"; }
g fetch -q origin develop "$branch"
echo "--- develop is $(g rev-list --count "$(g merge-base origin/develop "origin/$branch")..origin/develop") commits past this PR's base"
gh run list -R "$R" -b develop -L 20 --json workflowName,conclusion \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ set -euo pipefail
# shellcheck source=lib.sh
. "$(dirname "$0")/lib.sh"
[ $# -gt 0 ] || { echo "usage: cleanup.sh <pr>..." >&2 && exit 2; }
g() { git -C "$DELPHI_REPOS/argos" "$@"; }
g() { git -C "$DELPHI_WORKTREES/argos/.bare" "$@"; }
for pr in "$@"; do
read -r state branch author < <(gh pr view "$pr" -R "$R" --json state,headRefName,author -q '"\(.state) \(.headRefName) \(.author.login)"')
case $author in *dependabot*) ;; *) echo "#$pr skipped: author is $author" && continue ;; esac
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 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.
You're in Delphi workspace `s.app.argos.argos-dev` (branch `ws/s.app.argos.argos-dev`); code repos are cloned at `repos/<repo>/`, and separately checked out as worktrees under `worktrees/<repo>/` (`.delphi/setup.sh` makes the default branch's). Work in worktrees: make each new branch one 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; a clone at repos/<name> (worktrees from it: worktrees/<name>/<branch>)
repos: # `<name>: <git-url>`: code you change; a clone at repos/<name>, and separately worktrees/<name>/<branch> (default branch first)
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 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.
You're in Delphi workspace `s.app.argos.experimental` (branch `ws/s.app.argos.experimental`); code repos are cloned at `repos/<repo>/`, and separately checked out as worktrees under `worktrees/<repo>/` (`.delphi/setup.sh` makes the default branch's). Work in worktrees: make each new branch one 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; a clone at repos/<name> (worktrees from it: worktrees/<name>/<branch>)
repos: # `<name>: <git-url>`: code you change; a clone at repos/<name>, and separately worktrees/<name>/<branch> (default branch first)
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
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Delphi workspace

You're in Delphi workspace `s.app.nero.nero-experimental` (branch `ws/s.app.nero.nero-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.
You're in Delphi workspace `s.app.nero.nero-experimental` (branch `ws/s.app.nero.nero-experimental`); code repos are cloned at `repos/<repo>/`, and separately checked out as worktrees under `worktrees/<repo>/` (`.delphi/setup.sh` makes the default branch's). Work in worktrees: make each new branch one 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
Loading
Loading