diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json deleted file mode 100644 index b821342..0000000 --- a/.claude-plugin/marketplace.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "delphi", - "owner": { - "name": "Northeastern Electric Racing" - }, - "description": "Delphi's Claude Code plugins: context shared by the workspaces under a folder.", - "plugins": [ - { - "name": "delphi", - "source": "./software/plugins/claude/default", - "description": "Delphi's mod for every workspace: /ws-delphi opens a pane of workspace cards grouped by project; select one, then Switch workspace (.delphi/switch.sh). /ws-delphi --web opens the same cards in a browser tab." - } - ] -} diff --git a/software/application-software/argos/workspaces/argos-dev/.claude/settings.json b/.claude/settings.json similarity index 100% rename from software/application-software/argos/workspaces/argos-dev/.claude/settings.json rename to .claude/settings.json diff --git a/software/application-software/workspace-inherit/.claude/skills/address-pr-comments/SKILL.md b/.claude/skills/address-pr-comments/SKILL.md similarity index 100% rename from software/application-software/workspace-inherit/.claude/skills/address-pr-comments/SKILL.md rename to .claude/skills/address-pr-comments/SKILL.md diff --git a/software/application-software/workspace-inherit/.claude/skills/address-pr-comments/scripts/fetch-feedback.sh b/.claude/skills/address-pr-comments/scripts/fetch-feedback.sh similarity index 100% rename from software/application-software/workspace-inherit/.claude/skills/address-pr-comments/scripts/fetch-feedback.sh rename to .claude/skills/address-pr-comments/scripts/fetch-feedback.sh diff --git a/software/application-software/workspace-inherit/.claude/skills/address-pr-comments/scripts/github.sh b/.claude/skills/address-pr-comments/scripts/github.sh similarity index 100% rename from software/application-software/workspace-inherit/.claude/skills/address-pr-comments/scripts/github.sh rename to .claude/skills/address-pr-comments/scripts/github.sh diff --git a/software/application-software/workspace-inherit/.claude/skills/commit/SKILL.md b/.claude/skills/commit/SKILL.md similarity index 100% rename from software/application-software/workspace-inherit/.claude/skills/commit/SKILL.md rename to .claude/skills/commit/SKILL.md diff --git a/software/application-software/workspace-inherit/.claude/skills/consolidate-spikes/SKILL.md b/.claude/skills/consolidate-spikes/SKILL.md similarity index 100% rename from software/application-software/workspace-inherit/.claude/skills/consolidate-spikes/SKILL.md rename to .claude/skills/consolidate-spikes/SKILL.md diff --git a/.claude/skills/create-ticket/SKILL.md b/.claude/skills/create-ticket/SKILL.md index 11a8ef1..210a059 100644 --- a/.claude/skills/create-ticket/SKILL.md +++ b/.claude/skills/create-ticket/SKILL.md @@ -1,11 +1,66 @@ --- name: create-ticket -description: Draft and file a GitHub issue (idea, spike, epic, or dev work) on Delphi from its issue templates. Use whenever the user wants to create, file, or log a Delphi ticket, issue, idea, spike, epic, bug, or task. +description: Draft and file a GitHub issue (idea, spike, epic, or dev work) on an application-software repo (Argos, Nero) from the repo's issue templates, or rewrite an existing issue into them. Use whenever the user wants to create, file, write up, or log a ticket, issue, idea, spike, epic, bug, or task, including an out-of-scope idea that comes up mid-work. --- -Follow the shared rules in `software/application-software/workspace-inherit/.claude/skills/create-ticket/SKILL.md`, with these Delphi specifics: +# Create ticket -- Repo: Northeastern-Electric-Racing/Delphi (base branch `main`); templates in `.github/ISSUE_TEMPLATE/`. -- Labels: the template's category and a written-by label; Delphi has no area labels. -- Vocabulary: `docs/design.md`'s terms (workspace, ws branch, refresh, propose, `workspace-inherit/`). -- Diagrams: show the branches and folders a change touches (main, `ws/*`, `.delphi/`, CI), before and after. +These are the ticket conventions for every application-software repo. The repo's own `.github/ISSUE_TEMPLATE` holds only the fields (`gh api repos///contents/.github/ISSUE_TEMPLATE/ -q .content | base64 -d`); follow each field's description. + +First load the project's `ticket-conventions` skill (inherited from the project's `workspace-inherit/`) for its repo, area labels, vocabulary, and diagrams. If none is enabled, ask which repo. + +## Workflow + +idea → spikes → epic → dev work, or a standalone spike → dev work + +| Ticket | What it is | Issue type | Parent | +|---|---|---|---| +| Idea | What could be built and why. Its areas to explore are things to improve or problems to solve, each with approaches worth trying. | none | none | +| Spike | One approach to try on one area of an idea (it needn't cover the whole area), or a small standalone improvement: what is tried and the hypothesis. Findings go in a comment and a draft PR (`report-spike`), not the ticket. | none | its idea, if any | +| Epic | Work too large for one dev work ticket: the goal and whole-epic outcomes, not a walkthrough of each ticket. A new issue linking the idea or spike it came from in "From". | Feature | none | +| Dev work | Any implementation work: testable requirements, Notes for gotchas and pointers to code. Large work is cut into vertical slices (see Dev work below). | Feature, Bug, or Task | its epic, if any | + +If unsure, a small, clear change is dev work, a small unknown is a spike, and a big unexplored thing is an idea. Ideas and spikes explore work, so they get no issue type; bug, feature, and task are issue types, never labels. + +## Writing + +How every ticket reads, on any project: + +- Short and plain. Write for someone new to the project: explain project-specific terms, and use the project's vocabulary (its `ticket-conventions` says where it lives; check the code for current names). +- Outcomes, not implementation: say what changes and why, not how to build it. A rationale gives the reasoning, not a history of the problem. +- No prescriptions on ideas and spikes. Ideas name open options to weigh, not a plan or a recommended pick; spikes state what to learn and leave the how to whoever picks it up. +- Facts, not instructions: Notes and context transfer hold facts (where code lives, current behavior, constraints, links), not steps or a proposed solution. Context transfer (optional on spikes, epics, and dev work) starts with a short summary, then the raw context. +- Unknowns stay open questions in Notes; don't guess. +- Title: concise and imperative, no prefixes (except a spike's area). +- Requirements: clear, broad checkboxes, each a testable outcome rather than an implementation step; 3-5, never more than 7. If it needs more, split the ticket. +- Backticks: at most three inline uses per body; name files and identifiers in plain text. Diagram and context-transfer blocks don't count. +- Size: keep ideas short; one small enough to just try is a spike. + +## Dev work + +- One ticket by default. Split only when the work is too large for one PR or parts could run in parallel. +- When split, cut vertical slices: each goes end to end through every part it touches (e.g. backend through UI), not one layer, and works and is testable on its own. Cut for the most parallel work; mark a slice that must wait as blocked by the one it waits on (see File). + +## Spikes + +- One approach, not a set to choose between. If a spike reads "X or Y", it is two spikes. +- Prefer an idea with a few spikes (often 2-4) under it; a spike can also stand alone, or with siblings, to explore an area. Several spikes can take on the same area in different ways. +- Title it `: `, with the area a short kebab-case name its siblings share (`graph-saving: Save a graph to a file and re-upload it`). An area may cover more than one of an idea's bullets. A lone small improvement needs no prefix. +- Sibling spikes share the context transfer's summary and common facts; each adds only the facts particular to its approach. +- An idea needn't get all its spikes at once: file an area's spikes when someone is ready to try them. +- Done: its findings are posted, review feedback is addressed, and the lead's latest review on its draft PR is an approval (GitHub's Approve), including when the recommendation is to drop the approach. A done spike stays open until `consolidate-spikes` closes it. + +## Draft + +- Check the code first: the work may be done or already tracked. +- One `### ` per field in template order, following each field's description; omit empty optional fields. +- Diagrams: required on epics, optional on dev work. The project's `ticket-conventions` says what they show. +- Labels: the template's category (`idea`, `spike`, `epic`, `dev work`), one written-by (`by: human` if the user dictated it, `by: ai-assisted` if they gave the substance, `by: ai` if you wrote it, including rewrites), and at least one of the project's area labels. +- Rewriting an old ticket: keep its intent and assignees; bring it up to these rules and update vocabulary, labels, issue type, and parent. +- Folding one ticket into another: add it as a requirement on the target, then close it as not planned. Every close gets a one-line comment saying why. + +## File + +Check for open duplicates, then show the full draft (title, type if any, labels, parent, body) in the chat, not only in a file. File or edit only what the user OKs. + +Use the REST API (GraphQL may be blocked): POST repos///issues with title, body, labels, the issue type from the table, and the user as assignee (on a spike, whoever will run it; ask), then, if it has a parent, POST repos///issues//sub_issues with the new issue's id. If it waits on another issue, POST repos///issues//dependencies/blocked_by with the blocking issue's id. Report the URL. diff --git a/software/application-software/argos/workspaces/argos-dev/.claude/skills/dependabot-cleanup/SKILL.md b/.claude/skills/dependabot-cleanup/SKILL.md similarity index 100% rename from software/application-software/argos/workspaces/argos-dev/.claude/skills/dependabot-cleanup/SKILL.md rename to .claude/skills/dependabot-cleanup/SKILL.md diff --git a/software/application-software/argos/workspaces/argos-dev/.claude/skills/dependabot-cleanup/scripts/ci.sh b/.claude/skills/dependabot-cleanup/scripts/ci.sh similarity index 100% rename from software/application-software/argos/workspaces/argos-dev/.claude/skills/dependabot-cleanup/scripts/ci.sh rename to .claude/skills/dependabot-cleanup/scripts/ci.sh diff --git a/software/application-software/argos/workspaces/argos-dev/.claude/skills/dependabot-cleanup/scripts/cleanup.sh b/.claude/skills/dependabot-cleanup/scripts/cleanup.sh similarity index 100% rename from software/application-software/argos/workspaces/argos-dev/.claude/skills/dependabot-cleanup/scripts/cleanup.sh rename to .claude/skills/dependabot-cleanup/scripts/cleanup.sh diff --git a/software/application-software/argos/workspaces/argos-dev/.claude/skills/dependabot-cleanup/scripts/lib.sh b/.claude/skills/dependabot-cleanup/scripts/lib.sh similarity index 100% rename from software/application-software/argos/workspaces/argos-dev/.claude/skills/dependabot-cleanup/scripts/lib.sh rename to .claude/skills/dependabot-cleanup/scripts/lib.sh diff --git a/software/application-software/argos/workspaces/argos-dev/.claude/skills/dependabot-cleanup/scripts/list.sh b/.claude/skills/dependabot-cleanup/scripts/list.sh similarity index 100% rename from software/application-software/argos/workspaces/argos-dev/.claude/skills/dependabot-cleanup/scripts/list.sh rename to .claude/skills/dependabot-cleanup/scripts/list.sh diff --git a/software/application-software/argos/workspaces/argos-dev/.claude/skills/dependabot-cleanup/scripts/merge.sh b/.claude/skills/dependabot-cleanup/scripts/merge.sh similarity index 100% rename from software/application-software/argos/workspaces/argos-dev/.claude/skills/dependabot-cleanup/scripts/merge.sh rename to .claude/skills/dependabot-cleanup/scripts/merge.sh diff --git a/software/application-software/argos/workspaces/argos-dev/.claude/skills/dependabot-cleanup/scripts/rebase.sh b/.claude/skills/dependabot-cleanup/scripts/rebase.sh similarity index 100% rename from software/application-software/argos/workspaces/argos-dev/.claude/skills/dependabot-cleanup/scripts/rebase.sh rename to .claude/skills/dependabot-cleanup/scripts/rebase.sh diff --git a/software/application-software/argos/workspaces/argos-dev/.claude/skills/dependabot-cleanup/scripts/validate.sh b/.claude/skills/dependabot-cleanup/scripts/validate.sh similarity index 100% rename from software/application-software/argos/workspaces/argos-dev/.claude/skills/dependabot-cleanup/scripts/validate.sh rename to .claude/skills/dependabot-cleanup/scripts/validate.sh diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/implement/SKILL.md b/.claude/skills/implement/SKILL.md similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/implement/SKILL.md rename to .claude/skills/implement/SKILL.md diff --git a/software/workspace-inherit/.claude/skills/journal/SKILL.md b/.claude/skills/journal/SKILL.md similarity index 100% rename from software/workspace-inherit/.claude/skills/journal/SKILL.md rename to .claude/skills/journal/SKILL.md diff --git a/software/workspace-inherit/.claude/skills/journal/scripts/capture.sh b/.claude/skills/journal/scripts/capture.sh similarity index 100% rename from software/workspace-inherit/.claude/skills/journal/scripts/capture.sh rename to .claude/skills/journal/scripts/capture.sh diff --git a/software/workspace-inherit/.claude/skills/new-worktree/SKILL.md b/.claude/skills/new-worktree/SKILL.md similarity index 100% rename from software/workspace-inherit/.claude/skills/new-worktree/SKILL.md rename to .claude/skills/new-worktree/SKILL.md diff --git a/software/application-software/workspace-inherit/.claude/skills/open-pr/SKILL.md b/.claude/skills/open-pr/SKILL.md similarity index 100% rename from software/application-software/workspace-inherit/.claude/skills/open-pr/SKILL.md rename to .claude/skills/open-pr/SKILL.md diff --git a/software/application-software/workspace-inherit/.claude/skills/open-pr/scripts/pr-checks.sh b/.claude/skills/open-pr/scripts/pr-checks.sh similarity index 100% rename from software/application-software/workspace-inherit/.claude/skills/open-pr/scripts/pr-checks.sh rename to .claude/skills/open-pr/scripts/pr-checks.sh diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/SKILL.md b/.claude/skills/pr-conventions/SKILL.md similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/SKILL.md rename to .claude/skills/pr-conventions/SKILL.md diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/scripts/lint.sh b/.claude/skills/pr-conventions/scripts/lint.sh similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/pr-conventions/scripts/lint.sh rename to .claude/skills/pr-conventions/scripts/lint.sh diff --git a/software/application-software/workspace-inherit/.claude/skills/report-spike/SKILL.md b/.claude/skills/report-spike/SKILL.md similarity index 100% rename from software/application-software/workspace-inherit/.claude/skills/report-spike/SKILL.md rename to .claude/skills/report-spike/SKILL.md diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/run-local/SKILL.md b/.claude/skills/run-local/SKILL.md similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/run-local/SKILL.md rename to .claude/skills/run-local/SKILL.md diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/run-local/scripts/run-local.sh b/.claude/skills/run-local/scripts/run-local.sh similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/run-local/scripts/run-local.sh rename to .claude/skills/run-local/scripts/run-local.sh diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/run-local/scripts/serve.sh b/.claude/skills/run-local/scripts/serve.sh similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/run-local/scripts/serve.sh rename to .claude/skills/run-local/scripts/serve.sh diff --git a/software/workspace-inherit/.claude/skills/setup-workspace/SKILL.md b/.claude/skills/setup-workspace/SKILL.md similarity index 100% rename from software/workspace-inherit/.claude/skills/setup-workspace/SKILL.md rename to .claude/skills/setup-workspace/SKILL.md diff --git a/software/workspace-inherit/.claude/skills/switch-workspace/SKILL.md b/.claude/skills/switch-workspace/SKILL.md similarity index 100% rename from software/workspace-inherit/.claude/skills/switch-workspace/SKILL.md rename to .claude/skills/switch-workspace/SKILL.md diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/ticket-conventions/SKILL.md b/.claude/skills/ticket-conventions/SKILL.md similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/ticket-conventions/SKILL.md rename to .claude/skills/ticket-conventions/SKILL.md diff --git a/software/application-software/workspace-inherit/.claude/skills/update-pr/SKILL.md b/.claude/skills/update-pr/SKILL.md similarity index 100% rename from software/application-software/workspace-inherit/.claude/skills/update-pr/SKILL.md rename to .claude/skills/update-pr/SKILL.md diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md b/.claude/skills/verify-graph/SKILL.md similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md rename to .claude/skills/verify-graph/SKILL.md diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/check.js b/.claude/skills/verify-graph/scripts/check.js similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/check.js rename to .claude/skills/verify-graph/scripts/check.js diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/check.sh b/.claude/skills/verify-graph/scripts/check.sh similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/check.sh rename to .claude/skills/verify-graph/scripts/check.sh diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/open.sh b/.claude/skills/verify-graph/scripts/open.sh similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/open.sh rename to .claude/skills/verify-graph/scripts/open.sh diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/perf.js b/.claude/skills/verify-graph/scripts/perf.js similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/perf.js rename to .claude/skills/verify-graph/scripts/perf.js diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/perf.sh b/.claude/skills/verify-graph/scripts/perf.sh similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/perf.sh rename to .claude/skills/verify-graph/scripts/perf.sh diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/seed.sh b/.claude/skills/verify-graph/scripts/seed.sh similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/seed.sh rename to .claude/skills/verify-graph/scripts/seed.sh diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/select-run.sh b/.claude/skills/verify-graph/scripts/select-run.sh similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/select-run.sh rename to .claude/skills/verify-graph/scripts/select-run.sh diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-telemetry/SKILL.md b/.claude/skills/verify-telemetry/SKILL.md similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/verify-telemetry/SKILL.md rename to .claude/skills/verify-telemetry/SKILL.md diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-telemetry/scripts/check-topic.sh b/.claude/skills/verify-telemetry/scripts/check-topic.sh similarity index 100% rename from software/application-software/argos/workspace-inherit/.claude/skills/verify-telemetry/scripts/check-topic.sh rename to .claude/skills/verify-telemetry/scripts/check-topic.sh diff --git a/.gitattributes b/.gitattributes index f85d5d0..4965641 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ -# LF everywhere, so the scripts (ci/, tools/, tests/, .delphi/) run in Git Bash even with core.autocrlf=true +# LF everywhere, so .delphi/setup.sh runs in Git Bash even with core.autocrlf=true * text=auto eol=lf diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index fa7bd15..0000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,3 +0,0 @@ -# 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 diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 3ba13e0..0000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1 +0,0 @@ -blank_issues_enabled: false diff --git a/.github/ISSUE_TEMPLATE/dev-work.yml b/.github/ISSUE_TEMPLATE/dev-work.yml deleted file mode 100644 index 6eb6751..0000000 --- a/.github/ISSUE_TEMPLATE/dev-work.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Dev work -description: Implementation work of any kind (feature, bug, or task). Set the issue type to match. -labels: [dev work] -body: - - type: markdown - attributes: - value: | - One template for all implementation work. Set the issue **type** (Feature, Bug, or Task) instead of picking a different template. - If this belongs to an epic, add it as a sub-issue of the epic. - After filing, add a written-by label (`by: human`, `by: ai`, `by: ai-assisted`). - - type: textarea - id: what - attributes: - label: What - description: | - The change in a few sentences. - For a bug: what happens, what should happen, and steps to reproduce. - validations: - required: true - - type: textarea - id: diagram - attributes: - label: Diagram - description: Optional. Illustrate the change. Mermaid (in a mermaid code block), ASCII, or an uploaded image. - - type: textarea - id: requirements - attributes: - label: Requirements - description: What must be true for this to be done. Clear, broad, testable checkboxes. Aim for 3-5; never more than 7. - value: "- [ ] " - validations: - required: true - - type: textarea - id: notes - attributes: - label: Notes - description: Optional. Anything that helps whoever picks this up, such as links to spikes, PRs or docs, gotchas, and constraints. - - type: textarea - id: context-transfer - attributes: - label: Context transfer - description: Optional. A dump of context for whoever picks this up (person or agent). Start with a short summary, then the raw context. - value: | - SUMMARY - - CONTEXT - render: text diff --git a/.github/ISSUE_TEMPLATE/epic.yml b/.github/ISSUE_TEMPLATE/epic.yml deleted file mode 100644 index 8853a14..0000000 --- a/.github/ISSUE_TEMPLATE/epic.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Epic -description: Work too large for one ticket, broken into dev work tickets. -type: Feature -labels: [epic] -body: - - type: markdown - attributes: - value: | - An epic groups dev work tickets; link them as sub-issues. - If it came from an idea or spike, link it below and close it as completed. - After filing, add a written-by label (`by: human`, `by: ai`, `by: ai-assisted`). - - type: input - id: from - attributes: - label: From - description: The idea or spike this epic came from, if any. - placeholder: "#123" - - type: textarea - id: goal - attributes: - label: Goal - description: What this delivers, and for whom, in a few sentences. - validations: - required: true - - type: textarea - id: approach - attributes: - label: Approach - description: Optional. The chosen approach, if one is decided. - - type: textarea - id: diagram - attributes: - label: Diagram - description: Illustrate the change, ideally before and after. Mermaid (in a mermaid code block), ASCII, or an uploaded image. - validations: - required: true - - type: textarea - id: out-of-scope - attributes: - label: Out of scope - description: What this epic deliberately does not cover. - value: "- " - - type: textarea - id: requirements - attributes: - label: Requirements - description: What must be true for the epic to be done. Clear, broad checkboxes. Aim for 3-5; never more than 7. - value: "- [ ] " - validations: - required: true - - type: textarea - id: context-transfer - attributes: - label: Context transfer - description: Optional. A dump of context for whoever picks this up (person or agent). Start with a short summary, then the raw context. - value: | - SUMMARY - - CONTEXT - render: text diff --git a/.github/ISSUE_TEMPLATE/idea.yml b/.github/ISSUE_TEMPLATE/idea.yml deleted file mode 100644 index 78362e4..0000000 --- a/.github/ISSUE_TEMPLATE/idea.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Idea -description: A feature or improvement worth exploring. Ideas are explored through spikes and, once settled, become an epic. -labels: [idea] -body: - - type: markdown - attributes: - value: | - **Pipeline:** idea → spikes (sub-issues) → epic → dev work. - Keep an idea short. If it is small enough to just try, file a spike instead. - Don't prescribe a solution. Each area stays open for one or more spikes to explore, not a chosen design. - After filing, add a written-by label (`by: human`, `by: ai`, `by: ai-assisted`). - - type: textarea - id: idea - attributes: - label: Idea - description: One or two sentences. What could we build, and for whom? Describe the outcome, not the implementation. - placeholder: Let a folder share skills with every workspace below it. - validations: - required: true - - type: textarea - id: rationale - attributes: - label: Rationale - description: Why this idea is good and worth exploring. The reasoning behind it, not a history of the problem. - validations: - required: true - - type: textarea - id: areas - attributes: - label: Areas to explore - description: | - The areas to improve or problems to solve, each one for one or more spikes to explore. Each bullet names an area and a few approaches worth trying. - Each spike tries one approach to its area. It doesn't have to cover the whole area, and an area can have several spikes, each trying a different approach. - List areas that need real exploration or design decisions, not questions with quick answers. Name approaches to weigh, not a plan or a recommended pick. - value: | - - **Area:** approach, approach, or approach. - validations: - required: true diff --git a/.github/ISSUE_TEMPLATE/spike.yml b/.github/ISSUE_TEMPLATE/spike.yml deleted file mode 100644 index 828e03b..0000000 --- a/.github/ISSUE_TEMPLATE/spike.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Spike -description: Explore one approach to an idea, or try a small standalone improvement. Draft PRs welcome. -labels: [spike] -body: - - type: markdown - attributes: - value: | - A spike lays out what to explore and what we expect. It does **not** hold answers: post findings as comments and link draft PRs. It's done when the lead approves its draft PR. - Don't prescribe a solution. Describe what to learn and leave the how to whoever picks it up. - One approach per spike, not a set to choose between. Title it `: `, the area shared by its siblings. Prefer filing it under an idea (as a sub-issue), but a spike can stand alone. - After filing, add a written-by label (`by: human`, `by: ai`, `by: ai-assisted`). - - type: textarea - id: exploring - attributes: - label: Exploring - description: The one approach being tried, broadly. Say what it is, not how to build it or how to run the exploration. - validations: - required: true - - type: textarea - id: hypothesis - attributes: - label: Hypothesis - description: What we expect this approach to prove, in one or two sentences. Reviewers judge the draft PRs and findings against it. - validations: - required: true - - type: textarea - id: context-transfer - attributes: - label: Context transfer - description: Optional. A dump of context for whoever picks this up (person or agent). Start with a short summary, then the raw context. Facts only (where code lives, current behavior, constraints, links), not instructions or a proposed solution. - value: | - SUMMARY - - CONTEXT - render: text diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 2cca24c..0000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,31 +0,0 @@ - - -## Changes - - - -## Diagram - - - -## Testing - - - -- - -## Notes - - - -## Checklist - -- [ ] `ci/check.sh .` and `bash tests/e2e.sh` pass -- [ ] Version bumped if a `.delphi/manifest.yml` file changed -- [ ] No merge conflicts -- [ ] Request reviewers & ping on Slack - -Closes # diff --git a/CLAUDE.md b/CLAUDE.md index 1d042da..057cbdd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,91 +1,65 @@ -# Delphi — developing it - -Delphi stores NER's AI-harness context. Each workspace is a folder `software/**/workspaces//` -on `main`, named by the short names of its folders and its leaf, joined by dots (`.delphi/names.sh`; -a folder's short name is its `short-name` file, else its name: `s.app.argos.argos-dev`); branch `ws/` has that folder as its repo root. `ci/sync.sh` keeps them in sync with -subtree merges: **refresh** (main → `ws/`) and **propose** (`ws/` → PR to main via -`propose/`). 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 - -- `ci/sync.sh [refresh|propose] []`: refresh and/or propose each workspace (both by default). - Runs on pushes to main and `ws/**`. -- `ci/check.sh []`: 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. Its PR and - sync's propose PRs fill `.github/pull_request_template.md`'s sections (keep them in step) and are - labelled `by: ai` (new-workspace: `--by ai-assisted|human` when the user says so). -- `ci/plugins.sh`: writes `.claude-plugin/marketplace.json` from the plugin sets - (`software/**/plugins///`, named `[.]`; a folder's scope is its - `plugins/scope`, else its `short-name`, else its name), each Claude Code workspace's `workspace.yml` `plugins:` defaults (the - `default` set of every folder above), and its `.claude/settings.json` (enabled sets, and the SessionStart hook that sets `$DELPHI_ROOT`; never edit - it by hand). `ci/render.sh` calls it for main-side plugin output; sync keeps branch-selected - plugin sets active while their proposal to main is pending. -- `.delphi/{setup,new-worktree,switch,park,plugins}.sh`: the scripts every workspace runs (setup.sh - runs `plugins.sh`, which makes this clone's local `@delphi` installs what the workspace enables and - uninstalls ones the marketplace dropped, so plugin changes need no migration); `.delphi/paths.sh` - is the layout (`DELPHI_ROOT`, `DELPHI_WORKTREES`, …) that they and skill scripts source; `.delphi/names.sh` names every - workspace (dotted short names; setup, switch, sync, check and the migration all use it); park.sh also moves - the root folders under a workspace's `park:` in `workspace.yml` on a switch, and setup.sh excludes them. Only here: sync - puts `.delphi/` at the root of every `ws/*` branch and strips it from proposals. -- `.delphi/manifest.yml` (Delphi's files and their `version:`), `.delphi/versions` (one line per - version, with its hash from `.delphi/version.sh`), `.delphi/migrations/-.sh` (clone - cleanup, run by `setup.sh`). -- `templates/workspace/`: `workspace.yml`, `CLAUDE.md` (`{{name}}`, `{{folder}}`), the managed - `.github/workflows/delphi.yml` every workspace carries unchanged. The general skills are in - `software/workspace-inherit/.claude/skills/`; Codex adds its bootstrap from `templates/harnesses/` - to the common instruction base once at creation. -- `software/plugins/claude/default/`: the `delphi` plugin set, a mod whose `/ws-delphi` pane switches - workspaces (`hooks/register.tsx`, tests in `tests/ws.test.ts`, run by `claude plugin test`); - `/ws-delphi --web` serves the same cards in a browser tab (`web/server.py`, `web/index.html`). -- `software/…/workspaces//`: the workspaces. Org structure is plain directories. A project - folder (the one holding `workspaces/`) may add `README.md`, `AUTHORING.md`, and `workspace-defaults/` - (translated once into a new workspace there). Existing source layouts stay intact; optional - `source.yml` declares a different authoring format. Any org/project folder may add `workspace-inherit/`; - CI prepares inheritance in temporary staging and refresh copies it only to ws branches. - Their `workspace.generated` records ownership; `opt-out:` transfers a native path to the workspace. - Main keeps owned native files and canonical sources, never inherited copies or ledgers. -- `.github/workflows/delphi.yml` (identical to the template's copy), `.github/CODEOWNERS`; issue templates (idea, spike, epic, dev work) and the PR template in `.github/`, filed with the `create-ticket` skill (`.claude/skills/`). -- `tests/e2e.sh`: end-to-end test in a throwaway sandbox (bare origin, stub `gh` logging to `gh.log`). -- `ci/render.sh [--check] [--workspace ] [ []]`: update plugin - output, or prepare inherited native files and ledgers in optional temporary staging. Main-side - checks reject managed copies, ledgers and ownership collisions; inherited output is never committed there. - `ci/harnesses.sh` reads `ci/harnesses/.sh` through pure `harness_field` queries; - `ci/sources.sh` reads independently selected formats; `ci/inherit.sh` resolves sources. - `ci/managed.sh` shares ownership logic with sync, whose refresh - copies staged output. Every workspace must explicitly declare its harness. Codex uses - `.delphi/exec.sh` to initialize helper commands in independent shells. - -## Rules - -- Keep it small: fewest lines that implement the design; a short header comment per script. - Prefer deleting to adapting. -- Don't list out groups of things in docs or comments (`docs/design.md`, README, CLAUDE.md, script - headers): name the file or key that holds them ("the folders in `.delphi/park.list`", "each repo - under `repos:`"), never its entries. A copied list goes stale. Runtime tools: bash, git, and `gh` (only to open or update PRs). -- Every script: `#!/usr/bin/env bash`, `set -euo pipefail`, `shellcheck`-clean. -- Keep Claude skill sources under workspace-inherit/.claude/skills with their metadata intact. - Each descriptor owns `translate_skill`; native metadata conversion, identifier mappings and - helper bootstrap affect only generated output. Write skills once in Claude format; translate - identifiers and feature bullets, never exact source sentences or per-skill copies. Validation - rejects unmapped Claude identifiers in other harnesses; qualified code-repository paths stay literal. - Shared-source paths and opt-out keys follow `docs/design.md`'s portable-path rule; existing owned - workspace filenames are unaffected. - Skill scripts stay harness-independent (SKILL.md uses the Agent Skills format): call scripts by - their path in the skill's folder, `bash scripts/ - - diff --git a/software/plugins/claude/default/web/server.py b/software/plugins/claude/default/web/server.py deleted file mode 100644 index f255868..0000000 --- a/software/plugins/claude/default/web/server.py +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/env python3 -"""The delphi mod's browser view of /ws-delphi: python3 web/server.py serves index.html (the same -cards: select one, then Switch workspace) on 127.0.0.1 at a random port, and prints its URL, the -first line on stdout. The page asks it for .delphi/switch.sh --list and runs switch.sh ; each -switch prints `switched `, which the mod reads to update its pane. Pull runs switch.sh on the -workspace the clone is on (fetch, fast-forward, setup.sh) and prints `pulled `. The mod starts it with -/ws-delphi --web (or the pane's Open in browser) and stops it with the session; by hand, Ctrl-C ends it. - -Only this machine reaches it, and only a page holding the URL's token: any web page the browser has -open can send requests to 127.0.0.1, so every request needs the token in its path and a Host of -127.0.0.1 or localhost (against DNS rebinding), and a switch needs a JSON body (which a page of -another origin can't send without a preflight, which this answers with nothing). Python 3.7+, stdlib. -""" -import http.server -import json -import secrets -import subprocess -import sys -import threading -from pathlib import Path - -root = Path(sys.argv[1] if len(sys.argv) > 1 else '.').resolve() -switch = root / '.delphi' / 'switch.sh' -if not switch.is_file(): - sys.exit('server: no .delphi/switch.sh in ' + str(root) + '; give a Delphi clone') -token = secrets.token_urlsafe(18) -page = (Path(__file__).parent / 'index.html').read_bytes() -busy = threading.Lock() # one switch at a time -switching = '' # the workspace being switched to (or pulled), while one runs - - -def run(argv, timeout): - try: - return subprocess.run(argv, cwd=root, capture_output=True, text=True, timeout=timeout) - except (OSError, subprocess.TimeoutExpired) as err: - return subprocess.CompletedProcess(argv, -1, '', str(err)) - - -def last_line(text, otherwise): - lines = [line for line in text.strip().splitlines() if line.strip()] - return lines[-1] if lines else otherwise - - -def state(): - listed = run(['bash', str(switch), '--list'], 60) - lines = [line for line in listed.stdout.splitlines() if line.strip()] - return { - 'here': next((line[2:].split(' ')[0] for line in lines if line.startswith('* ')), ''), - 'workspaces': [line[2:] for line in lines], - 'isDirty': run(['git', 'diff', '--quiet', 'HEAD', '--'], 10).returncode != 0, - 'switching': switching, - 'error': '' if listed.returncode == 0 else 'Could not list the workspaces: ' + last_line(listed.stderr, 'switch.sh --list failed'), - } - - -def do_switch(name): - global switching - if not busy.acquire(blocking=False): - return 409, {'ok': False, 'message': 'a switch to ' + switching + ' is running'} - try: - switching = name - done = run(['bash', str(switch), name], 600) - finally: - switching = '' - busy.release() - if done.returncode != 0: - return 200, {'ok': False, 'message': last_line(done.stderr, 'switch.sh failed')} - print('switched ' + name, flush=True) - return 200, {'ok': True, 'message': last_line(done.stdout, 'switched')} - - -def do_pull(): - global switching - here = state()['here'] - if not here: - return 400, {'ok': False, 'message': 'this clone is on no workspace'} - if not busy.acquire(blocking=False): - return 409, {'ok': False, 'message': 'a switch to ' + switching + ' is running'} - leaf = here.split('.')[-1] - try: - switching = here - before = run(['git', 'rev-parse', 'HEAD'], 10).stdout.strip() - done = run(['bash', str(switch), here], 600) - after = run(['git', 'rev-parse', 'HEAD'], 10).stdout.strip() - finally: - switching = '' - busy.release() - if done.returncode != 0: - return 200, {'ok': False, 'message': 'Not pulled: ' + last_line(done.stderr, 'switch.sh failed')} - if 'diverged' in done.stderr: - return 200, {'ok': False, 'message': last_line(done.stderr, 'diverged from origin')} - count = run(['git', 'rev-list', '--count', before + '..' + after], 10).stdout.strip() if before and after and before != after else '0' - n = int(count or 0) - message = leaf + ' is up to date with origin' if n == 0 else 'Pulled %d commit%s into %s' % (n, '' if n == 1 else 's', leaf) - print('pulled ' + message, flush=True) - return 200, {'ok': True, 'message': message} - - -class Handler(http.server.BaseHTTPRequestHandler): - def send(self, status, body, kind): - self.send_response(status) - self.send_header('Content-Type', kind) - self.send_header('Content-Length', str(len(body))) - self.send_header('Cache-Control', 'no-store') - self.send_header('Referrer-Policy', 'no-referrer') # the token stays in this page - self.send_header('Content-Security-Policy', "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; connect-src 'self'; frame-ancestors 'none'") - self.end_headers() - self.wfile.write(body) - - def json(self, status, value): - self.send(status, json.dumps(value).encode(), 'application/json') - - def route(self): - """The path after the token, or None (and the refusal sent) for a request not from the page.""" - port = self.server.server_address[1] - if self.headers.get('Host') not in ('127.0.0.1:%d' % port, 'localhost:%d' % port): - self.send(403, b'forbidden\n', 'text/plain') - return None - prefix = '/' + token + '/' - if not self.path.split('?')[0].startswith(prefix): - self.send(404, b'not found\n', 'text/plain') - return None - return self.path.split('?')[0][len(prefix):] - - def do_GET(self): - path = self.route() - if path == '': - self.send(200, page, 'text/html; charset=utf-8') - elif path == 'api/state': - self.json(200, state()) - elif path is not None: - self.send(404, b'not found\n', 'text/plain') - - def do_POST(self): - path = self.route() - if path is None: - return - if path not in ('api/switch', 'api/pull'): - return self.send(404, b'not found\n', 'text/plain') - if self.headers.get('Content-Type', '').split(';')[0].strip() != 'application/json': - return self.json(415, {'ok': False, 'message': 'send JSON'}) - if path == 'api/pull': - return self.json(*do_pull()) - try: - name = json.loads(self.rfile.read(int(self.headers.get('Content-Length') or 0)) or b'{}').get('name', '') - except (ValueError, AttributeError): - name = '' - if not isinstance(name, str) or not name: - return self.json(400, {'ok': False, 'message': 'no workspace named'}) - self.json(*do_switch(name)) - - def log_message(self, format, *args): # quiet: stderr is the mod's debug log - pass - - -server = http.server.ThreadingHTTPServer(('127.0.0.1', 0), Handler) -print('http://127.0.0.1:%d/%s/' % (server.server_address[1], token), flush=True) -try: - server.serve_forever() -except KeyboardInterrupt: - pass diff --git a/software/plugins/scope b/software/plugins/scope deleted file mode 100644 index 29e09b6..0000000 --- a/software/plugins/scope +++ /dev/null @@ -1 +0,0 @@ -delphi diff --git a/software/short-name b/software/short-name deleted file mode 100644 index b478595..0000000 --- a/software/short-name +++ /dev/null @@ -1 +0,0 @@ -s diff --git a/templates/harnesses/codex/AGENTS.md b/templates/harnesses/codex/AGENTS.md deleted file mode 100644 index 7ad803f..0000000 --- a/templates/harnesses/codex/AGENTS.md +++ /dev/null @@ -1,9 +0,0 @@ - - -## Workspace setup - -Work from the checked-out workspace root, where `workspace.yml` is. Run `bash .delphi/paths.sh` from this root to learn its absolute path, and run `bash .delphi/setup.sh` when the repositories have not been set up. - -Shell exports may not persist between commands or reach independently launched sub-agents. Run skill helpers through `bash /.delphi/exec.sh bash /scripts/