From 2fa965192760df0c4d8844d09d339d28351ad0d3 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 9 Jul 2026 06:17:25 +0200 Subject: [PATCH 01/16] Centralize agent descriptions as docs and add AGENTS.md/CLAUDE.md pointers --- AGENTS.md | 30 ++++++++ CLAUDE.md | 5 ++ src/docs/Agents/agent-author.md | 49 +++++++++++++ src/docs/Agents/define.md | 58 ++++++++++++++++ src/docs/Agents/implement.md | 69 +++++++++++++++++++ src/docs/Agents/index.md | 26 +++++++ src/docs/Agents/reviewer.md | 59 ++++++++++++++++ src/docs/Agents/security-reviewer.md | 47 +++++++++++++ .../Ways-of-Working/Agentic-Development.md | 10 +-- .../Principles/AI-First-Development.md | 4 +- src/docs/index.md | 1 + src/zensical.toml | 8 +++ 12 files changed, 359 insertions(+), 7 deletions(-) create mode 100644 AGENTS.md create mode 100644 CLAUDE.md create mode 100644 src/docs/Agents/agent-author.md create mode 100644 src/docs/Agents/define.md create mode 100644 src/docs/Agents/implement.md create mode 100644 src/docs/Agents/index.md create mode 100644 src/docs/Agents/reviewer.md create mode 100644 src/docs/Agents/security-reviewer.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..097b69a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,30 @@ +# Agents + +This repository is the central documentation for the MSX ecosystem. Everything an agent needs to work here — and the roles agents play across the ecosystem — is documentation, read the same way a new teammate would. + +## Start here + +1. Read this file, then the [README](README.md) for what this repository is and how it builds. +2. Read the [Ways of Working](https://msxorg.github.io/docs/Ways-of-Working/) — how work flows from idea to delivery. +3. Load the [Coding Standards](https://msxorg.github.io/docs/Coding-Standards/) relevant to the change. Repo-local linter config wins where it disagrees. + +## Roles + +Agent behaviour is authored once, as documentation, in the [Agents](https://msxorg.github.io/docs/Agents/) section. Use the role that fits the task: + +- [Define](https://msxorg.github.io/docs/Agents/define/) — capture, refine, and plan a change into an issue. +- [Implement](https://msxorg.github.io/docs/Agents/implement/) — deliver a planned issue as a review-ready pull request. +- [Reviewer](https://msxorg.github.io/docs/Agents/reviewer/) — review a pull request for delivery, taste, and security. +- [Security Reviewer](https://msxorg.github.io/docs/Agents/security-reviewer/) — a structured, defensive security pass. +- [Agent Author](https://msxorg.github.io/docs/Agents/agent-author/) — create and maintain these roles and pointers. + +## How work happens here + +- Work on a `/` branch in its own [worktree](https://msxorg.github.io/docs/Ways-of-Working/Git-Worktrees/); open a **draft** pull request early. +- Run the [Copilot review loop](https://msxorg.github.io/docs/Ways-of-Working/Contribution-Workflow/) until it is clean. +- Mark ready only when the change meets the [Definition of Ready for Review](https://msxorg.github.io/docs/Ways-of-Working/Definition-of-Ready-and-Done/), then enable auto-merge. +- Documentation is validated by lint, link, and index checks — see the [README](README.md). + +## The rule + +This file points; it never defines. Process knowledge lives in the docs and is referenced by canonical URL — never copied here. See [Agentic Development](https://msxorg.github.io/docs/Ways-of-Working/Agentic-Development/). diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..23ade99 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +# CLAUDE.md + +@AGENTS.md + +Claude Code does not read `AGENTS.md` automatically, so this file imports it — the line above pulls in the shared instructions every agent follows. Keep any Claude-specific notes below the import; everything else lives in [AGENTS.md](AGENTS.md) and the documentation it points to. diff --git a/src/docs/Agents/agent-author.md b/src/docs/Agents/agent-author.md new file mode 100644 index 0000000..8d3db9e --- /dev/null +++ b/src/docs/Agents/agent-author.md @@ -0,0 +1,49 @@ +--- +title: Agent Author +description: Create and maintain the agent role descriptions and the per-repository pointer files that reference them. +--- + +# Agent Author + +Create and maintain the agent roles in this section, and the per-repository pointer files that reference them. Every role description is grounded in the [Ways of Working](../Ways-of-Working/index.md); every pointer file stays thin. Agent Author keeps descriptions and pointers honest — it does not encode standards into either. + +## When to use + +Create a new agent role, update an existing one, review agent quality, or refactor a bloated agent file back into a thin pointer over the docs. + +## Flow + +### 1. Gather requirements + +1. Identify the role — the single job it owns, and its boundary. +2. Identify the docs pages that govern that role; confirm they exist. +3. Identify what the role must **not** do — boundaries prevent scope creep. + +### 2. Author the description + +Write the role as a page in this section, following the shape of its siblings: front matter (`title`, `description`), a one-paragraph role and boundary, when to use, a numbered flow, operating rules, and a "Where this connects" list. + +- **Link, don't inline.** If a standard exists in the docs, link to it — never paste it in. +- **Procedural, not conversational.** Numbered imperatives, no filler. +- **Keyword-rich description.** The front-matter `description` is the discovery surface. + +### 3. Keep pointers thin + +A repository never carries a copy of a role. Its `AGENTS.md` — and the `CLAUDE.md` that imports it — point to these pages and add only repo-specific nuance and the genuinely tool-specific settings (permission scopes, model choice) that cannot be expressed as a pointer. When a new runtime is adopted, add a thin pointer; do not move process knowledge into it. See [Agentic Development](../Ways-of-Working/Agentic-Development.md). + +### 4. Validate + +1. Front-matter YAML parses cleanly. +2. Every link resolves, and the body duplicates no doc content. +3. The role is added to the navigation so its index row generates. + +## Operating rules + +1. Docs are the source of truth. If a standard is missing, propose adding it to the docs — do not embed it in an agent. +2. One agent, one job. Multiple roles mean multiple pages. +3. Update the navigation when adding or removing a role. + +## Where this connects + +- [Agentic Development](../Ways-of-Working/Agentic-Development.md) — the pointer model this maintains. +- [Documentation Model](../Ways-of-Working/Documentation-Model.md) — how these pages stay evergreen. diff --git a/src/docs/Agents/define.md b/src/docs/Agents/define.md new file mode 100644 index 0000000..01d2a4b --- /dev/null +++ b/src/docs/Agents/define.md @@ -0,0 +1,58 @@ +--- +title: Define +description: Capture, refine, and plan a change into an actionable issue ready for implementation. +--- + +# Define + +Take something someone wants — a feature, a bug, an improvement, external feedback, or a production signal — and turn it into a planned, actionable issue. The output is either a single Task with its three sections populated, or a decomposed initiative with structured sub-issues. Define plans work; it does not build it. + +## When to use + +Capture a desire for change, write an issue, plan work, decompose an epic, refine a bug report, create sub-issues, structure a feature request, or turn feedback into a task. + +## Input + +A description of a desired change, a feedback issue from a non-contributor (treated as input, never modified), a platform signal (error, failed run, alert), or an existing issue to refine. + +## Flow + +### 1. Capture + +Turn the input into an issue with Section 1 (context and request). + +1. Search for duplicates first — propose consolidation rather than creating a new issue. +2. Frame from the user's perspective per [Issue Format](../Ways-of-Working/Issue-Format.md). +3. Acceptance criteria must be user-observable and testable. + +### 2. Refine + +Ground the issue so anyone reading it agrees on what "done" means, up to the [Definition of Ready](../Ways-of-Working/Definition-of-Ready-and-Done.md). + +1. Pain before solution — push back on implementation-framed requests. +2. Make assumptions explicit. +3. Acceptance criteria answerable yes or no by a non-author. +4. Ask one question at a time when interactive. + +### 3. Plan + +Decide how the work will happen and record the decisions. + +1. **Task** — one deliverable, one pull request. Populate the technical decisions and the implementation plan per [Issue Format](../Ways-of-Working/Issue-Format.md). +2. **Larger work** — decompose into child issues per [Issue Hierarchy](../Ways-of-Working/Issue-Hierarchy.md). +3. Find the minimum viable path — spike, then proof of concept, then minimum viable product, then improve. +4. Record decisions with their rationale and the alternatives considered. +5. Resolve open questions before finishing; defer anything that does not block this slice to a follow-up issue. + +## Operating rules + +1. Tone is impersonal. The issue description is the source of truth; comments record what changed. +2. External references are hyperlinks. +3. Do not modify a feedback issue from a non-contributor — create an internal issue and cross-link. +4. Stop when the issue is plannable. Do not build, branch, or open pull requests — that is [Implement](implement.md). + +## Where this connects + +- [Workflow](../Ways-of-Working/Workflow.md) — the loop this opens. +- [Issue Format](../Ways-of-Working/Issue-Format.md) and [Issue Hierarchy](../Ways-of-Working/Issue-Hierarchy.md) — issue structure and levels. +- [Definition of Ready and Done](../Ways-of-Working/Definition-of-Ready-and-Done.md) — the readiness bar this aims for. diff --git a/src/docs/Agents/implement.md b/src/docs/Agents/implement.md new file mode 100644 index 0000000..7ccf43b --- /dev/null +++ b/src/docs/Agents/implement.md @@ -0,0 +1,69 @@ +--- +title: Implement +description: Take a planned issue and deliver it as a review-ready pull request — branch, build, self-review, and finalize. +--- + +# Implement + +Take a planned issue and deliver working software in a review-ready pull request. Owns the full delivery loop: branching, coding, committing, opening the pull request, tracking progress, running the automated review loop, responding to feedback, and finalizing the release note. Implement builds; it does not plan from scratch or review others' work. + +## When to use + +Implement an issue, build a feature, fix a bug, create a branch, open a pull request, respond to review feedback, or finalize a pull request. Given an initiative rather than a task, pick the next unfinished sub-issue. + +## Input + +A Task issue number or URL with its three sections populated. + +## Flow + +### 1. Orient + +1. Read the issue fully — all three sections per [Issue Format](../Ways-of-Working/Issue-Format.md). +2. Read the repository README first per [README-Driven Context](../Ways-of-Working/Readme-Driven-Context.md). +3. Identify the stack and load the relevant [Coding Standards](../Coding-Standards/index.md). Repo-local linter config wins where it disagrees with a published standard. + +### 2. Branch and draft pull request + +Use [git worktrees](../Ways-of-Working/Git-Worktrees.md) for every issue. + +1. Create a worktree from the default branch per [Branching and Merging](../Ways-of-Working/Branching-and-Merging.md). +2. Push an initial commit and immediately open a **draft** pull request so CI attaches from the first push. +3. Link the issue with a closing keyword, and assign the pull request. + +### 3. Build + +For each task in the plan: + +1. Implement the change and self-review the staged diff. +2. Commit per [Commit Conventions](../Ways-of-Working/Commit-Conventions.md) — one logical change per commit. +3. Update the issue as each task completes — do not batch. +4. Push regularly so CI runs against current work. + +When the plan is wrong, stop and document the conflict in a comment, then update the plan before resuming. Out-of-scope problems go to [Define](define.md). + +### 4. Self-review and respond + +1. Run the [Copilot review loop](../Ways-of-Working/Contribution-Workflow.md#the-copilot-review-loop) until it reports a clean round. +2. Triage each thread and CI failure per [Review Etiquette](../Ways-of-Working/Review-Etiquette.md): fix in scope and propagate the same fix elsewhere; file a follow-up for out-of-scope; reply, then resolve. + +### 5. Finalize and hand off + +When the change meets the [Definition of Ready for Review](../Ways-of-Working/Definition-of-Ready-and-Done.md): + +1. Finalize the title, release-note description, and label per [PR Format](../Ways-of-Working/PR-Format.md). +2. Mark the pull request ready and enable auto-merge per [Branching and Merging](../Ways-of-Working/Branching-and-Merging.md). + +## Operating rules + +1. Micro-commits, one logical change each, with descriptive messages. +2. Progress is visible — issues updated as tasks complete, not in bulk. +3. Draft pull request from the start; stay in the issue's scope. +4. Mark ready only when the change meets the Definition of Ready for Review — never with open tasks. +5. No planning from scratch (that is [Define](define.md)); no reviewing others' pull requests (that is [Reviewer](reviewer.md)). + +## Where this connects + +- [Contribution Workflow](../Ways-of-Working/Contribution-Workflow.md) — the draft-first loop this runs. +- [Definition of Ready and Done](../Ways-of-Working/Definition-of-Ready-and-Done.md) — the gate this hands off at. +- [PR Format](../Ways-of-Working/PR-Format.md) and [Branching and Merging](../Ways-of-Working/Branching-and-Merging.md) — packaging and landing. diff --git a/src/docs/Agents/index.md b/src/docs/Agents/index.md new file mode 100644 index 0000000..0d0efa6 --- /dev/null +++ b/src/docs/Agents/index.md @@ -0,0 +1,26 @@ +--- +title: Agents +description: The roles agents play across the ecosystem — authored once as documentation and pointed to from each repository. +--- + +# Agents + +The roles agents play across the MSX ecosystem, authored once as documentation. Each page describes one role — its job, when to use it, and the steps it follows — grounded in the [Ways of Working](../Ways-of-Working/index.md) rather than restating them. + +These descriptions are the **single source for agent behaviour**. A repository does not carry its own copy; its `AGENTS.md` and `CLAUDE.md` are thin pointers to these pages ([Agentic Development](../Ways-of-Working/Agentic-Development.md)). Humans read the same pages a new teammate would. + +The lifecycle runs **Define → Implement → Review**: capture and plan the work, build it in a pull request, then review it. Two supporting roles — Security Reviewer and Agent Author — run alongside. + +## Contents + + + +| Page | Description | +| --- | --- | +| [Define](define.md) | Capture, refine, and plan a change into an actionable issue ready for implementation. | +| [Implement](implement.md) | Take a planned issue and deliver it as a review-ready pull request — branch, build, self-review, and finalize. | +| [Reviewer](reviewer.md) | Review someone else's pull request for delivery, taste, security, and undiscussed decisions. | +| [Security Reviewer](security-reviewer.md) | A structured, defensive security review that reports vulnerabilities as an actionable responsible-disclosure issue. | +| [Agent Author](agent-author.md) | Create and maintain the agent role descriptions and the per-repository pointer files that reference them. | + + diff --git a/src/docs/Agents/reviewer.md b/src/docs/Agents/reviewer.md new file mode 100644 index 0000000..7090a58 --- /dev/null +++ b/src/docs/Agents/reviewer.md @@ -0,0 +1,59 @@ +--- +title: Reviewer +description: Review someone else's pull request for delivery, taste, security, and undiscussed decisions. +--- + +# Reviewer + +Look at a pull request as the person on the other side of the contribution. Verify the work delivers the linked issue, applies good taste, respects security, and does not quietly introduce decisions that were not discussed. The Reviewer comments and approves; it does not change code, fix CI, or merge. + +## When to use + +Review a pull request, check a change for delivery, verify acceptance criteria, or assess taste and standards. For a security-focused pass, use [Security Reviewer](security-reviewer.md). + +## Input + +A pull request number or URL. If the pull request was authored by the reviewing identity, switch to self-review: write findings to the terminal, and do not post public comments (an author cannot review their own pull request). + +## Flow + +### 1. Read the issue + +The three sections are the contract. The pull request should deliver the acceptance criteria using the recorded approach. Note any gap. + +### 2. Read the README + +Some "missing" things are by design per the documented scope ([README-Driven Context](../Ways-of-Working/Readme-Driven-Context.md)). + +### 3. Assess the diff + +Check each dimension per [Review Etiquette](../Ways-of-Working/Review-Etiquette.md): + +- **Delivery** — does the diff meet the acceptance criteria, without scope it did not ask for? +- **Taste** — readability, naming, structure, tests that exercise behaviour. +- **Security** — input validation, no secrets in logs, SHA-pinned actions, least privilege. Escalate a deep pass to [Security Reviewer](security-reviewer.md). +- **Documentation** — updated where user-facing behaviour changed. +- **Tests** — new behaviour has tests; bugs get regression tests. + +### 4. Post the review + +Use severity prefixes per [Review Etiquette](../Ways-of-Working/Review-Etiquette.md): `Blocking:`, `Question:`, `Suggestion:`, `Nit:`. Out-of-scope suggestions become new issues, not blocking comments. + +### 5. Approve + +An approval co-signs the change, so approve once the blocking concerns are resolved. The approving identity must not be the author and must not be the built-in Actions identity — approvals come from a separate reviewer identity per [Branching and Merging](../Ways-of-Working/Branching-and-Merging.md). With auto-merge enabled, the approval is what lands the change. + +## Operating rules + +1. Read the issue first; review against it. +2. Stay in the pull request's scope — beyond-issue suggestions are filed as new issues. +3. One concern per comment. +4. Apply repo standards; linter rules win where a standard is silent. +5. Security is non-negotiable. +6. No code changes, no CI fixing, and no merging from the Reviewer. + +## Where this connects + +- [Review Etiquette](../Ways-of-Working/Review-Etiquette.md) — tone, severity, and how to disagree well. +- [Branching and Merging](../Ways-of-Working/Branching-and-Merging.md) — who approves and how a change lands. +- [Security Reviewer](security-reviewer.md) — the dedicated security pass. diff --git a/src/docs/Agents/security-reviewer.md b/src/docs/Agents/security-reviewer.md new file mode 100644 index 0000000..a1e491a --- /dev/null +++ b/src/docs/Agents/security-reviewer.md @@ -0,0 +1,47 @@ +--- +title: Security Reviewer +description: A structured, defensive security review that reports vulnerabilities as an actionable responsible-disclosure issue. +--- + +# Security Reviewer + +A defensive security review on behalf of the code owner: identify vulnerabilities and attack vectors in source code and documentation, and produce a clear, actionable responsible-disclosure issue that remediates each finding. A defender's mindset, not an attacker's — and no working exploit code. + +## When to use + +Perform a security review, audit code for vulnerabilities, threat-model a change, or review OWASP Top 10 risks — injection, secrets exposure, path traversal, privilege escalation, supply-chain risk, information disclosure. + +## Scope + +### Source code + +- **Injection** — command, script, SQL, NoSQL, or LDAP injection. +- **Secrets** — hardcoded tokens, keys, or passwords committed to source. +- **Insecure deserialization** — unsafe evaluation of untrusted input. +- **Path traversal** — user-controlled input used to build file paths. +- **Privilege escalation** — actions running beyond least privilege. +- **Dependency and supply-chain risk** — floating versions, and actions referenced by a mutable tag rather than a pinned SHA. +- **Information disclosure** — stack traces or debug output that leak sensitive data. +- **Race conditions** — checks that can be bypassed between the check and the use. + +### Documentation + +- Misleading security guidance, exposed internal endpoints, overly permissive examples, and social-engineering surface. + +## Output + +For each finding, a structured block: severity, component, vulnerability class, OWASP category, a plain-language description, an attack path (no exploit code), evidence (file and line), a concrete mitigation, and references (CVE, CWE, or OWASP). Severity is one of Critical, High, Medium, Low, or Informational. + +After the review, open a security issue on the target repository titled `[Security Review] `, labelled `security`, with an executive summary followed by the finding blocks. Critical and High findings are flagged as priorities. + +## Constraints + +- Do not generate, execute, or suggest working exploit code or payloads. +- Do not access, exfiltrate, or modify data beyond what is needed to identify a vulnerability. +- Report only through the agreed channel — the issue on the target repository. +- On evidence of an active breach, stop and inform the owner so they can follow incident response. + +## Where this connects + +- [Review Etiquette](../Ways-of-Working/Review-Etiquette.md) — how findings are communicated. +- [Security](../Coding-Standards/Security.md) and [GitHub Actions](../Coding-Standards/GitHub-Actions.md) — the standards a finding cites. diff --git a/src/docs/Ways-of-Working/Agentic-Development.md b/src/docs/Ways-of-Working/Agentic-Development.md index a2b31ee..90150f4 100644 --- a/src/docs/Ways-of-Working/Agentic-Development.md +++ b/src/docs/Ways-of-Working/Agentic-Development.md @@ -55,8 +55,8 @@ This split follows [Repository Segmentation](Repository-Segmentation.md) and [RE Agent context is delivered through three layers, in priority order — the same three layers the [Principles](Principles/AI-First-Development.md#human-agent-coexistence) describe: 1. **Documentation.** The primary source. The published docs, READMEs, and issue bodies are written for humans and read natively by agents. -2. **Central agent configuration.** Organization-wide agent files in a `.github-private` repository. These are thin orchestrators built mostly from references to the docs — they define roles, boundaries, and procedural steps, never standards or conventions. -3. **Local repository files.** Per-repository instruction files for what is unique to a single repository, including the small amount of genuinely tool-specific configuration (permission scopes, path-scoped rules) that cannot be expressed as a pointer. +2. **Central agent descriptions.** The roles agents play — Define, Implement, Reviewer, and the rest — are authored once as documentation in the [Agents](../Agents/index.md) section. They describe roles, boundaries, and procedural steps, and they reference the ways of working; they never restate a standard or convention. +3. **Local pointer files.** Each repository carries an `AGENTS.md` — read natively by most agent runtimes — and a `CLAUDE.md` that imports it, pointing to the central descriptions and adding only repo-specific nuance and the small amount of genuinely tool-specific configuration (permission scopes, path-scoped rules) that cannot be expressed as a pointer. Any new runtime follows the same pattern, regardless of vendor: @@ -68,10 +68,10 @@ The context file and the entry points are pointers; the settings are the only ge ## Distribution -The two non-documentation layers have different distribution models, set by the level at which the platform supports shared configuration: +The two non-documentation layers have different distribution models: -- **Org-wide agent files** are distributed through a central `.github-private` repository and are available across every repository in the organization with zero per-repo maintenance. -- **Per-repository files** — context files and path-scoped instruction files — are seeded from a template repository and kept current across existing repositories by a sync mechanism. +- **Central agent descriptions** live in the [Agents](../Agents/index.md) section of this site and are referenced by canonical URL — one definition, available to every repository and runtime with no per-repo copy to maintain. +- **Per-repository pointer files** — `AGENTS.md`, the `CLAUDE.md` that imports it, and any path-scoped instruction files — are seeded from a template repository and kept current across existing repositories by a sync mechanism. Process knowledge is never added to a distributed config file. If an agent needs the branch strategy, it goes in [Branching and Merging](Branching-and-Merging.md) or the repo's `CONTRIBUTING.md`; if it needs a coding convention, it goes in the relevant [coding standard](../Coding-Standards/index.md). The config file only points — it never defines. diff --git a/src/docs/Ways-of-Working/Principles/AI-First-Development.md b/src/docs/Ways-of-Working/Principles/AI-First-Development.md index f3e11fc..5f9f10d 100644 --- a/src/docs/Ways-of-Working/Principles/AI-First-Development.md +++ b/src/docs/Ways-of-Working/Principles/AI-First-Development.md @@ -32,8 +32,8 @@ Agents are trained to read documentation. That is their natural skill. By keepin Agent context is delivered through three layers, in priority order: 1. **Documentation** — the primary source. Published docs at , READMEs, and issue bodies are written for humans and naturally consumable by agents. -2. **Central agent configuration** — organization-wide agent files in `.github-private`. Thin orchestrators built mostly from references to the docs. They define roles, boundaries, and procedural steps — not standards or conventions. -3. **Local repository files** — `.github/` instruction files and repo-level overrides for what is unique to a single repository. +2. **Central agent descriptions** — the roles agents play, authored once as documentation in the [Agents](../../Agents/index.md) section. They reference the ways of working and define roles, boundaries, and procedural steps — never standards or conventions. +3. **Local pointer files** — each repository's `AGENTS.md` (and the `CLAUDE.md` that imports it), pointing to the central descriptions and adding only repo-specific nuance and genuinely tool-specific settings. ## Augmentation, not replacement diff --git a/src/docs/index.md b/src/docs/index.md index f3c6203..9b135f8 100644 --- a/src/docs/index.md +++ b/src/docs/index.md @@ -47,6 +47,7 @@ Each area below carries its own index. Start here, read the descriptions, and fo | [Vision](Vision/index.md) | The mission and the philosophy of easy, fast, and safe. | | [Initiatives](Initiatives/index.md) | The products that make the vision real — PSModule, AzActions, TFActions, and the tools built along the way. | | [Ways of Working](Ways-of-Working/index.md) | How work happens across the ecosystem — for humans and agents alike. | +| [Agents](Agents/index.md) | The roles agents play across the ecosystem — authored once as documentation and pointed to from each repository. | | [Coding Standards](Coding-Standards/index.md) | The shared baseline every repository inherits, and the per-language standards that build on it. | | [Capabilities](Capabilities/index.md) | The capabilities the ecosystem builds, each documented by a spec (why and what) and a design (how and what). | | [Dictionary](Dictionary/index.md) | Shared vocabulary for the MSX ecosystem — the terms a reader or agent meets across these docs. | diff --git a/src/zensical.toml b/src/zensical.toml index 3efc528..c2259fa 100644 --- a/src/zensical.toml +++ b/src/zensical.toml @@ -57,6 +57,14 @@ nav = [ {"Continuous Practices" = "Ways-of-Working/Continuous-Practices.md"}, {"DevOps Reference" = "Ways-of-Working/DevOps-Reference.md"}, ]}, + {"Agents" = [ + "Agents/index.md", + {"Define" = "Agents/define.md"}, + {"Implement" = "Agents/implement.md"}, + {"Reviewer" = "Agents/reviewer.md"}, + {"Security Reviewer" = "Agents/security-reviewer.md"}, + {"Agent Author" = "Agents/agent-author.md"}, + ]}, {"Coding Standards" = [ "Coding-Standards/index.md", {"Naming" = "Coding-Standards/Naming.md"}, From 5bcba4983a6b3647b428477903a53ae867f46e89 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 9 Jul 2026 13:26:56 +0200 Subject: [PATCH 02/16] Add the workspace bootstrap: git-isolated local clone of docs + memory under ~/.msx Adds bootstrap/ (Initialize-MsxWorkspace.ps1 + AGENTS.template.md + README) and documents the model in Agentic Development. Each runtime's native entry file becomes a thin bootstrap that clones MSXOrg/docs and MSXOrg/memory to ~/.msx with repository-local git config; docs change via PR, memory pushes to main. --- bootstrap/AGENTS.template.md | 29 ++++++ bootstrap/Initialize-MsxWorkspace.ps1 | 89 +++++++++++++++++++ bootstrap/README.md | 38 ++++++++ .../Ways-of-Working/Agentic-Development.md | 11 +++ 4 files changed, 167 insertions(+) create mode 100644 bootstrap/AGENTS.template.md create mode 100644 bootstrap/Initialize-MsxWorkspace.ps1 create mode 100644 bootstrap/README.md diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md new file mode 100644 index 0000000..c2a0b7a --- /dev/null +++ b/bootstrap/AGENTS.template.md @@ -0,0 +1,29 @@ +# MSX workspace + +The single starting point for any agent, in any repository. Before doing anything else, make sure the central workspace exists locally, then read from it. + +## First — bootstrap the workspace + +The workspace is a git-isolated clone of the central repositories under `~/.msx`. Set it up (idempotent — clones what is missing, fast-forwards the rest): + +```powershell +if (-not (Test-Path ~/.msx/docs)) { git clone https://github.com/MSXOrg/docs.git ~/.msx/docs } +pwsh ~/.msx/docs/bootstrap/Initialize-MsxWorkspace.ps1 +``` + +This produces: + +- `~/.msx/docs` — how work is done: ways of working, coding standards, and agent roles. The same content published at . +- `~/.msx/memory` — what has been learned before: durable notes and prior session context. + +Each clone has repository-local git config only; it never touches the global git config or the repository being worked in. + +## Then — read before acting + +1. Read the relevant pages under `~/.msx/docs` for the task at hand. +2. Read `~/.msx/memory` for prior decisions, pitfalls, and context. + +## Two write rules + +- **Docs change through pull requests.** Branch inside `~/.msx/docs` and open a pull request; never push its `main`. +- **Memory pushes to main.** Commit and push notes directly inside `~/.msx/memory`; no pull request. diff --git a/bootstrap/Initialize-MsxWorkspace.ps1 b/bootstrap/Initialize-MsxWorkspace.ps1 new file mode 100644 index 0000000..8bb4b62 --- /dev/null +++ b/bootstrap/Initialize-MsxWorkspace.ps1 @@ -0,0 +1,89 @@ +#!/usr/bin/env pwsh +#Requires -Version 7.0 + +<# +.SYNOPSIS + Clone or update the MSX central workspace (docs + memory) in a git-isolated location under $HOME. + +.DESCRIPTION + The single starting point for every agent. It ensures the central + documentation and memory repositories exist locally under one dedicated + workspace, so an agent reads the same evergreen docs and the same prior + memory regardless of which repository it is working in. + + The workspace is deliberately kept separate from the repositories an agent + works in: + + - Each clone gets repository-local git config only. Nothing here touches the + global git config or the working repository's config. + - Documentation (MSXOrg/docs) is context and is changed through pull requests + only; this script never pushes its main branch. + - Memory (MSXOrg/memory) is append-only context; notes are committed and + pushed to main directly, without a pull request. + + The script is idempotent: it clones what is missing and fast-forwards what is + already present. + +.PARAMETER Root + The workspace root under which 'docs' and 'memory' are placed. Defaults to ~/.msx. + +.PARAMETER UserName + The git author name written to each clone's local config. + +.PARAMETER UserEmail + The git author email written to each clone's local config. + +.EXAMPLE + ./Initialize-MsxWorkspace.ps1 + Clones missing repositories and fast-forwards existing ones under ~/.msx. + +.EXAMPLE + ./Initialize-MsxWorkspace.ps1 -Root /work/.msx -Verbose + Uses a custom workspace root and logs each step. +#> +[CmdletBinding()] +param( + [Parameter()] + [string] $Root = (Join-Path $HOME '.msx'), + + [Parameter()] + [string] $UserName = 'Marius Storhaug', + + [Parameter()] + [string] $UserEmail = 'marstor@hotmail.com' +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$repositories = @( + [pscustomobject]@{ Name = 'docs'; Url = 'https://github.com/MSXOrg/docs.git'; Changes = 'pull requests' } + [pscustomobject]@{ Name = 'memory'; Url = 'https://github.com/MSXOrg/memory.git'; Changes = 'push to main' } +) + +New-Item -ItemType Directory -Force -Path $Root | Out-Null + +$results = foreach ($repo in $repositories) { + $path = Join-Path $Root $repo.Name + if (Test-Path (Join-Path $path '.git')) { + Write-Verbose "Updating $path" + git -C $path fetch origin --quiet + try { + git -C $path pull --ff-only --quiet + } catch { + Write-Warning "Could not fast-forward '$path' (local changes?). Left as-is." + } + } else { + Write-Verbose "Cloning $($repo.Url) into $path" + git clone --quiet $repo.Url $path + } + + # Isolated identity: repository-local config only, never global or inherited. + git -C $path config user.name $UserName + git -C $path config user.email $UserEmail + + [pscustomobject]@{ Repository = $repo.Name; Path = $path; Changes = $repo.Changes } +} + +$results | Format-Table -AutoSize +Write-Output 'MSX workspace ready. Read docs and memory here; docs change through pull requests, memory pushes to main.' diff --git a/bootstrap/README.md b/bootstrap/README.md new file mode 100644 index 0000000..0ebb8cd --- /dev/null +++ b/bootstrap/README.md @@ -0,0 +1,38 @@ +# Bootstrap + +The single starting point for agents: a git-isolated local clone of the MSX central repositories under `~/.msx`, plus the instruction that sends every agent there first. + +## Contents + +- `Initialize-MsxWorkspace.ps1` — idempotent setup. Clones `MSXOrg/docs` and `MSXOrg/memory` under `~/.msx`, fast-forwards them if present, and writes a repository-local git identity so the workspace never touches the global git config. +- `AGENTS.template.md` — the user-global entry instruction. It bootstraps the workspace, then points the agent at the docs and memory. Install it once per machine (below). + +## The model + +- `~/.msx/docs` is **read context** — the ways of working, coding standards, and agent roles. Changes to it go through **pull requests**. +- `~/.msx/memory` is **append-only context** — durable notes and session history. Changes to it are **pushed to main**. + +Keeping the workspace separate and git-isolated means an agent reads the same docs and memory in every repository, and its commits there use the workspace identity rather than whatever the working repository or the global config happens to be set to. + +## Install (once per machine) + +Run the bootstrap: + +```powershell +if (-not (Test-Path ~/.msx/docs)) { git clone https://github.com/MSXOrg/docs.git ~/.msx/docs } +pwsh ~/.msx/docs/bootstrap/Initialize-MsxWorkspace.ps1 +``` + +Wire it into the tools so it runs as the first instruction: + +- **Claude Code** reads `CLAUDE.md`. Add an import to `~/.claude/CLAUDE.md`: + + ```text + @~/.msx/docs/bootstrap/AGENTS.template.md + ``` + +- **Copilot** reads `AGENTS.md` natively. Use the contents of `AGENTS.template.md` as your user-level Copilot instructions, or copy it into a repository as `AGENTS.md`. + +## Identity + +The script writes a repository-local git identity to each clone (default: the maintainer's GitHub identity). Override it with `-UserName` / `-UserEmail`, or point it at a dedicated agent account when one exists. diff --git a/src/docs/Ways-of-Working/Agentic-Development.md b/src/docs/Ways-of-Working/Agentic-Development.md index 90150f4..47b13b3 100644 --- a/src/docs/Ways-of-Working/Agentic-Development.md +++ b/src/docs/Ways-of-Working/Agentic-Development.md @@ -75,6 +75,17 @@ The two non-documentation layers have different distribution models: Process knowledge is never added to a distributed config file. If an agent needs the branch strategy, it goes in [Branching and Merging](Branching-and-Merging.md) or the repo's `CONTRIBUTING.md`; if it needs a coding convention, it goes in the relevant [coding standard](../Coding-Standards/index.md). The config file only points — it never defines. +## The workspace bootstrap + +The natively-read entry file is a thin **bootstrap**, not a copy of the docs. Each runtime auto-loads its own file — Copilot reads `AGENTS.md`, Claude Code reads `CLAUDE.md` (which imports the same instructions) — and that file's first instruction is to make the central workspace present locally, then read from it. + +The workspace is a git-isolated clone of the central repositories under `~/.msx`: + +- `~/.msx/docs` — this documentation, read as local files. Changes to it go through pull requests. +- `~/.msx/memory` — durable notes and prior session context. Changes to it are pushed to main. + +Each clone carries repository-local git config only, so the workspace never touches the global git config or the repository the agent is working in. The setup is one idempotent script — [`bootstrap/Initialize-MsxWorkspace.ps1`](https://github.com/MSXOrg/docs/blob/main/bootstrap/Initialize-MsxWorkspace.ps1) — that clones what is missing and fast-forwards the rest. This keeps "start at the same point" literal: every agent, in every repository, begins from the same local docs and memory. + ## Where this connects - [Documentation Model](Documentation-Model.md) — the discipline this specification follows. From b100ba6df89fc6486432779022124c3b3e5a42a4 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 9 Jul 2026 13:35:10 +0200 Subject: [PATCH 03/16] Refine bootstrap per Copilot review: precise git-config wording, safe identity default, clone guard Say 'modifies' not 'touches' (git reads global config; script writes only repo-local) across the script, README, template, and Agentic Development; default identity to a GitHub noreply (no personal email in a public script); throw a clear error when the target path exists but is not a git repository. --- bootstrap/AGENTS.template.md | 2 +- bootstrap/Initialize-MsxWorkspace.ps1 | 10 +++++++--- bootstrap/README.md | 4 ++-- src/docs/Ways-of-Working/Agentic-Development.md | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md index c2a0b7a..b7f1b73 100644 --- a/bootstrap/AGENTS.template.md +++ b/bootstrap/AGENTS.template.md @@ -16,7 +16,7 @@ This produces: - `~/.msx/docs` — how work is done: ways of working, coding standards, and agent roles. The same content published at . - `~/.msx/memory` — what has been learned before: durable notes and prior session context. -Each clone has repository-local git config only; it never touches the global git config or the repository being worked in. +Each clone has repository-local git config only; it never modifies the global git config or the repository being worked in (git still reads them, but only repository-local config is written). ## Then — read before acting diff --git a/bootstrap/Initialize-MsxWorkspace.ps1 b/bootstrap/Initialize-MsxWorkspace.ps1 index 8bb4b62..45b940e 100644 --- a/bootstrap/Initialize-MsxWorkspace.ps1 +++ b/bootstrap/Initialize-MsxWorkspace.ps1 @@ -14,8 +14,9 @@ The workspace is deliberately kept separate from the repositories an agent works in: - - Each clone gets repository-local git config only. Nothing here touches the - global git config or the working repository's config. + - Each clone gets repository-local git config only. Nothing here modifies the + global git config or the working repository's config; git still reads global + and system config as usual, but this script writes only repository-local config. - Documentation (MSXOrg/docs) is context and is changed through pull requests only; this script never pushes its main branch. - Memory (MSXOrg/memory) is append-only context; notes are committed and @@ -50,7 +51,7 @@ param( [string] $UserName = 'Marius Storhaug', [Parameter()] - [string] $UserEmail = 'marstor@hotmail.com' + [string] $UserEmail = 'MariusStorhaug@users.noreply.github.com' ) Set-StrictMode -Version Latest @@ -74,6 +75,9 @@ $results = foreach ($repo in $repositories) { Write-Warning "Could not fast-forward '$path' (local changes?). Left as-is." } } else { + if (Test-Path $path) { + throw "Cannot clone into '$path': it exists but is not a git repository. Remove it or choose a different -Root." + } Write-Verbose "Cloning $($repo.Url) into $path" git clone --quiet $repo.Url $path } diff --git a/bootstrap/README.md b/bootstrap/README.md index 0ebb8cd..d66f13a 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -4,7 +4,7 @@ The single starting point for agents: a git-isolated local clone of the MSX cent ## Contents -- `Initialize-MsxWorkspace.ps1` — idempotent setup. Clones `MSXOrg/docs` and `MSXOrg/memory` under `~/.msx`, fast-forwards them if present, and writes a repository-local git identity so the workspace never touches the global git config. +- `Initialize-MsxWorkspace.ps1` — idempotent setup. Clones `MSXOrg/docs` and `MSXOrg/memory` under `~/.msx`, fast-forwards them if present, and writes a repository-local git identity so the workspace never modifies the global git config. - `AGENTS.template.md` — the user-global entry instruction. It bootstraps the workspace, then points the agent at the docs and memory. Install it once per machine (below). ## The model @@ -35,4 +35,4 @@ Wire it into the tools so it runs as the first instruction: ## Identity -The script writes a repository-local git identity to each clone (default: the maintainer's GitHub identity). Override it with `-UserName` / `-UserEmail`, or point it at a dedicated agent account when one exists. +The script writes a repository-local git identity to each clone. The default is the maintainer's GitHub **noreply** identity, so no personal email is written into git config and commits still attribute to the maintainer. Override it with `-UserName` / `-UserEmail`, or point it at a dedicated agent account when one exists. diff --git a/src/docs/Ways-of-Working/Agentic-Development.md b/src/docs/Ways-of-Working/Agentic-Development.md index 47b13b3..e5d8292 100644 --- a/src/docs/Ways-of-Working/Agentic-Development.md +++ b/src/docs/Ways-of-Working/Agentic-Development.md @@ -84,7 +84,7 @@ The workspace is a git-isolated clone of the central repositories under `~/.msx` - `~/.msx/docs` — this documentation, read as local files. Changes to it go through pull requests. - `~/.msx/memory` — durable notes and prior session context. Changes to it are pushed to main. -Each clone carries repository-local git config only, so the workspace never touches the global git config or the repository the agent is working in. The setup is one idempotent script — [`bootstrap/Initialize-MsxWorkspace.ps1`](https://github.com/MSXOrg/docs/blob/main/bootstrap/Initialize-MsxWorkspace.ps1) — that clones what is missing and fast-forwards the rest. This keeps "start at the same point" literal: every agent, in every repository, begins from the same local docs and memory. +Each clone carries repository-local git config only, so the workspace never modifies the global git config or the repository the agent is working in — git still reads them, but only repository-local config is written. The setup is one idempotent script — [`bootstrap/Initialize-MsxWorkspace.ps1`](https://github.com/MSXOrg/docs/blob/main/bootstrap/Initialize-MsxWorkspace.ps1) — that clones what is missing and fast-forwards the rest. This keeps "start at the same point" literal: every agent, in every repository, begins from the same local docs and memory. ## Where this connects From 4ad29f22b4308fe60f48c8d366c630ea5e48defd Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 9 Jul 2026 13:40:21 +0200 Subject: [PATCH 04/16] Remove UTF-8 BOM from the bootstrap script so the shebang works on Unix --- bootstrap/Initialize-MsxWorkspace.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/Initialize-MsxWorkspace.ps1 b/bootstrap/Initialize-MsxWorkspace.ps1 index 45b940e..f34e6f4 100644 --- a/bootstrap/Initialize-MsxWorkspace.ps1 +++ b/bootstrap/Initialize-MsxWorkspace.ps1 @@ -1,4 +1,4 @@ -#!/usr/bin/env pwsh +#!/usr/bin/env pwsh #Requires -Version 7.0 <# From d0799db3d9f13c392ba3bb554a2485ac5783e714 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 9 Jul 2026 13:46:23 +0200 Subject: [PATCH 05/16] Clarify identity default safety per Copilot review Reword the inline identity comment to say the script only writes repo-local config (git still reads global/system); add an explicit README warning to override -UserName/-UserEmail when not the maintainer. --- bootstrap/Initialize-MsxWorkspace.ps1 | 3 ++- bootstrap/README.md | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/bootstrap/Initialize-MsxWorkspace.ps1 b/bootstrap/Initialize-MsxWorkspace.ps1 index f34e6f4..142b8d9 100644 --- a/bootstrap/Initialize-MsxWorkspace.ps1 +++ b/bootstrap/Initialize-MsxWorkspace.ps1 @@ -82,7 +82,8 @@ $results = foreach ($repo in $repositories) { git clone --quiet $repo.Url $path } - # Isolated identity: repository-local config only, never global or inherited. + # Isolated identity: write repository-local config only. Git still reads + # global and system config; the script never writes to them. git -C $path config user.name $UserName git -C $path config user.email $UserEmail diff --git a/bootstrap/README.md b/bootstrap/README.md index d66f13a..aec132d 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -36,3 +36,5 @@ Wire it into the tools so it runs as the first instruction: ## Identity The script writes a repository-local git identity to each clone. The default is the maintainer's GitHub **noreply** identity, so no personal email is written into git config and commits still attribute to the maintainer. Override it with `-UserName` / `-UserEmail`, or point it at a dedicated agent account when one exists. + +> **Override this if you are not the maintainer.** With the default, commits — including memory pushes to `main` — are attributed to the maintainer's account. Pass `-UserName` and `-UserEmail` (for example `-UserEmail 'you@users.noreply.github.com'`), or point the script at a dedicated agent account, so your commits are attributed correctly. From d2cd418b7822f9aafd88a81c6e258f8790b7c0ab Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 9 Jul 2026 13:56:39 +0200 Subject: [PATCH 06/16] Make root AGENTS.md 'How work happens here' pure pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copilot review round 4 on #31: replace restated rules (branch naming, draft timing, mark-ready criteria) with links to Branching and Merging, Git Worktrees, Contribution Workflow, and Definition of Ready and Done — consistent with 'this file points; it never defines.' --- AGENTS.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 097b69a..858e19b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,10 +20,10 @@ Agent behaviour is authored once, as documentation, in the [Agents](https://msxo ## How work happens here -- Work on a `/` branch in its own [worktree](https://msxorg.github.io/docs/Ways-of-Working/Git-Worktrees/); open a **draft** pull request early. -- Run the [Copilot review loop](https://msxorg.github.io/docs/Ways-of-Working/Contribution-Workflow/) until it is clean. -- Mark ready only when the change meets the [Definition of Ready for Review](https://msxorg.github.io/docs/Ways-of-Working/Definition-of-Ready-and-Done/), then enable auto-merge. -- Documentation is validated by lint, link, and index checks — see the [README](README.md). +- [Branching and Merging](https://msxorg.github.io/docs/Ways-of-Working/Branching-and-Merging/) and [Git Worktrees](https://msxorg.github.io/docs/Ways-of-Working/Git-Worktrees/) — the branch model and where to work. +- [Contribution Workflow](https://msxorg.github.io/docs/Ways-of-Working/Contribution-Workflow/) — the draft-first, Copilot-review loop through to a ready pull request. +- [Definition of Ready and Done](https://msxorg.github.io/docs/Ways-of-Working/Definition-of-Ready-and-Done/) — when a change is ready for review and when it lands. +- This repository's build and checks — see the [README](README.md). ## The rule From b49002aa64c2b848e5f7c33a08f4cb6003093332 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 9 Jul 2026 14:05:56 +0200 Subject: [PATCH 07/16] Make the install snippet robust on a fresh machine Copilot review round 5 on #31: use \/Users/AD08640 (not ~, which git in PowerShell does not expand), check for docs/.git rather than the directory, and let git clone create the parent. Applied in both README and AGENTS.template. --- bootstrap/AGENTS.template.md | 7 +++++-- bootstrap/README.md | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md index b7f1b73..e32ab80 100644 --- a/bootstrap/AGENTS.template.md +++ b/bootstrap/AGENTS.template.md @@ -7,8 +7,11 @@ The single starting point for any agent, in any repository. Before doing anythin The workspace is a git-isolated clone of the central repositories under `~/.msx`. Set it up (idempotent — clones what is missing, fast-forwards the rest): ```powershell -if (-not (Test-Path ~/.msx/docs)) { git clone https://github.com/MSXOrg/docs.git ~/.msx/docs } -pwsh ~/.msx/docs/bootstrap/Initialize-MsxWorkspace.ps1 +$docs = Join-Path $HOME '.msx/docs' +if (-not (Test-Path (Join-Path $docs '.git'))) { + git clone https://github.com/MSXOrg/docs.git $docs +} +pwsh (Join-Path $docs 'bootstrap/Initialize-MsxWorkspace.ps1') ``` This produces: diff --git a/bootstrap/README.md b/bootstrap/README.md index aec132d..893d93a 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -19,8 +19,11 @@ Keeping the workspace separate and git-isolated means an agent reads the same do Run the bootstrap: ```powershell -if (-not (Test-Path ~/.msx/docs)) { git clone https://github.com/MSXOrg/docs.git ~/.msx/docs } -pwsh ~/.msx/docs/bootstrap/Initialize-MsxWorkspace.ps1 +$docs = Join-Path $HOME '.msx/docs' +if (-not (Test-Path (Join-Path $docs '.git'))) { + git clone https://github.com/MSXOrg/docs.git $docs +} +pwsh (Join-Path $docs 'bootstrap/Initialize-MsxWorkspace.ps1') ``` Wire it into the tools so it runs as the first instruction: From 8654038fdef098cd339b39d387cb639547890ba1 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 9 Jul 2026 14:22:38 +0200 Subject: [PATCH 08/16] Fail loudly on git errors; create parent dir in install snippets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copilot review round 6 on #31: check \0 after git (external commands don't throw in PowerShell), so a failed clone/fetch — e.g. the private memory repo without credentials — errors with an actionable message instead of silently reporting success; a non-fast-forward pull stays a warning. Both install snippets create the parent directory before cloning. Kept the script pure ASCII and BOM-free (shebang + PSSA). --- bootstrap/AGENTS.template.md | 1 + bootstrap/Initialize-MsxWorkspace.ps1 | 13 +++++++++---- bootstrap/README.md | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md index e32ab80..4ef8d3a 100644 --- a/bootstrap/AGENTS.template.md +++ b/bootstrap/AGENTS.template.md @@ -9,6 +9,7 @@ The workspace is a git-isolated clone of the central repositories under `~/.msx` ```powershell $docs = Join-Path $HOME '.msx/docs' if (-not (Test-Path (Join-Path $docs '.git'))) { + New-Item -ItemType Directory -Force -Path (Split-Path -Parent $docs) | Out-Null git clone https://github.com/MSXOrg/docs.git $docs } pwsh (Join-Path $docs 'bootstrap/Initialize-MsxWorkspace.ps1') diff --git a/bootstrap/Initialize-MsxWorkspace.ps1 b/bootstrap/Initialize-MsxWorkspace.ps1 index 142b8d9..2f27b05 100644 --- a/bootstrap/Initialize-MsxWorkspace.ps1 +++ b/bootstrap/Initialize-MsxWorkspace.ps1 @@ -69,10 +69,12 @@ $results = foreach ($repo in $repositories) { if (Test-Path (Join-Path $path '.git')) { Write-Verbose "Updating $path" git -C $path fetch origin --quiet - try { - git -C $path pull --ff-only --quiet - } catch { - Write-Warning "Could not fast-forward '$path' (local changes?). Left as-is." + if ($LASTEXITCODE -ne 0) { + throw "git fetch failed for '$path' (exit $LASTEXITCODE). Check network access and credentials for $($repo.Url)." + } + git -C $path pull --ff-only --quiet + if ($LASTEXITCODE -ne 0) { + Write-Warning "Could not fast-forward '$path' (local changes or diverged history). Left as-is." } } else { if (Test-Path $path) { @@ -80,6 +82,9 @@ $results = foreach ($repo in $repositories) { } Write-Verbose "Cloning $($repo.Url) into $path" git clone --quiet $repo.Url $path + if ($LASTEXITCODE -ne 0) { + throw "git clone failed for $($repo.Url) (exit $LASTEXITCODE). Check access and credentials (MSXOrg/memory is private)." + } } # Isolated identity: write repository-local config only. Git still reads diff --git a/bootstrap/README.md b/bootstrap/README.md index 893d93a..3e98acf 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -21,6 +21,7 @@ Run the bootstrap: ```powershell $docs = Join-Path $HOME '.msx/docs' if (-not (Test-Path (Join-Path $docs '.git'))) { + New-Item -ItemType Directory -Force -Path (Split-Path -Parent $docs) | Out-Null git clone https://github.com/MSXOrg/docs.git $docs } pwsh (Join-Path $docs 'bootstrap/Initialize-MsxWorkspace.ps1') From 623197d10ab70ad258f069b4b31464e970ae023e Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 9 Jul 2026 14:31:55 +0200 Subject: [PATCH 09/16] Match docs to actual fast-forward behavior (attempts, warns, leaves as-is) Copilot review round 7 on #31: the script help, Agentic Development, and AGENTS.template said the bootstrap 'fast-forwards' existing clones, but it only attempts a fast-forward and warns/leaves as-is on failure. Reworded to 'attempts to fast-forward' in all three. --- bootstrap/AGENTS.template.md | 2 +- bootstrap/Initialize-MsxWorkspace.ps1 | 5 +++-- src/docs/Ways-of-Working/Agentic-Development.md | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md index 4ef8d3a..74777c7 100644 --- a/bootstrap/AGENTS.template.md +++ b/bootstrap/AGENTS.template.md @@ -4,7 +4,7 @@ The single starting point for any agent, in any repository. Before doing anythin ## First — bootstrap the workspace -The workspace is a git-isolated clone of the central repositories under `~/.msx`. Set it up (idempotent — clones what is missing, fast-forwards the rest): +The workspace is a git-isolated clone of the central repositories under `~/.msx`. Set it up (idempotent — clones what is missing, attempts to fast-forward the rest): ```powershell $docs = Join-Path $HOME '.msx/docs' diff --git a/bootstrap/Initialize-MsxWorkspace.ps1 b/bootstrap/Initialize-MsxWorkspace.ps1 index 2f27b05..521e8d8 100644 --- a/bootstrap/Initialize-MsxWorkspace.ps1 +++ b/bootstrap/Initialize-MsxWorkspace.ps1 @@ -22,8 +22,9 @@ - Memory (MSXOrg/memory) is append-only context; notes are committed and pushed to main directly, without a pull request. - The script is idempotent: it clones what is missing and fast-forwards what is - already present. + The script is idempotent: it clones what is missing and attempts to + fast-forward what is already present, leaving a repository unchanged (with a + warning) when it cannot fast-forward. .PARAMETER Root The workspace root under which 'docs' and 'memory' are placed. Defaults to ~/.msx. diff --git a/src/docs/Ways-of-Working/Agentic-Development.md b/src/docs/Ways-of-Working/Agentic-Development.md index e5d8292..1842933 100644 --- a/src/docs/Ways-of-Working/Agentic-Development.md +++ b/src/docs/Ways-of-Working/Agentic-Development.md @@ -84,7 +84,7 @@ The workspace is a git-isolated clone of the central repositories under `~/.msx` - `~/.msx/docs` — this documentation, read as local files. Changes to it go through pull requests. - `~/.msx/memory` — durable notes and prior session context. Changes to it are pushed to main. -Each clone carries repository-local git config only, so the workspace never modifies the global git config or the repository the agent is working in — git still reads them, but only repository-local config is written. The setup is one idempotent script — [`bootstrap/Initialize-MsxWorkspace.ps1`](https://github.com/MSXOrg/docs/blob/main/bootstrap/Initialize-MsxWorkspace.ps1) — that clones what is missing and fast-forwards the rest. This keeps "start at the same point" literal: every agent, in every repository, begins from the same local docs and memory. +Each clone carries repository-local git config only, so the workspace never modifies the global git config or the repository the agent is working in — git still reads them, but only repository-local config is written. The setup is one idempotent script — [`bootstrap/Initialize-MsxWorkspace.ps1`](https://github.com/MSXOrg/docs/blob/main/bootstrap/Initialize-MsxWorkspace.ps1) — that clones what is missing and attempts to fast-forward the rest, leaving a repository as-is if it cannot. This keeps "start at the same point" literal: every agent, in every repository, begins from the same local docs and memory. ## Where this connects From 5902961132b45562217804e2c08d3be551ca4121 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 9 Jul 2026 14:49:04 +0200 Subject: [PATCH 10/16] Finish fast-forward wording, guard snippets, warn on default identity, clarify entry file Copilot review round 8 on #31: reword the remaining 'fast-forwards' overstatements (script .EXAMPLE, README bullet); guard both install snippets against a path that exists but is not a git repo; emit a runtime warning when the default maintainer identity is used; and clarify in Agentic Development that the bootstrap is the user-global entry, distinct from the per-repo AGENTS.md/CLAUDE.md pointers. --- bootstrap/AGENTS.template.md | 3 +++ bootstrap/Initialize-MsxWorkspace.ps1 | 6 +++++- bootstrap/README.md | 5 ++++- src/docs/Ways-of-Working/Agentic-Development.md | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md index 74777c7..aec1bc6 100644 --- a/bootstrap/AGENTS.template.md +++ b/bootstrap/AGENTS.template.md @@ -8,6 +8,9 @@ The workspace is a git-isolated clone of the central repositories under `~/.msx` ```powershell $docs = Join-Path $HOME '.msx/docs' +if ((Test-Path $docs) -and -not (Test-Path (Join-Path $docs '.git'))) { + throw "$docs exists but is not a git repository. Remove it and re-run." +} if (-not (Test-Path (Join-Path $docs '.git'))) { New-Item -ItemType Directory -Force -Path (Split-Path -Parent $docs) | Out-Null git clone https://github.com/MSXOrg/docs.git $docs diff --git a/bootstrap/Initialize-MsxWorkspace.ps1 b/bootstrap/Initialize-MsxWorkspace.ps1 index 521e8d8..aed04a5 100644 --- a/bootstrap/Initialize-MsxWorkspace.ps1 +++ b/bootstrap/Initialize-MsxWorkspace.ps1 @@ -37,7 +37,7 @@ .EXAMPLE ./Initialize-MsxWorkspace.ps1 - Clones missing repositories and fast-forwards existing ones under ~/.msx. + Clones missing repositories and attempts to fast-forward existing ones under ~/.msx. .EXAMPLE ./Initialize-MsxWorkspace.ps1 -Root /work/.msx -Verbose @@ -58,6 +58,10 @@ param( Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' +if (-not $PSBoundParameters.ContainsKey('UserEmail')) { + Write-Warning "Using the default maintainer identity ($UserName <$UserEmail>). Pass -UserName / -UserEmail to attribute your own commits (memory pushes to main)." +} + $repositories = @( [pscustomobject]@{ Name = 'docs'; Url = 'https://github.com/MSXOrg/docs.git'; Changes = 'pull requests' } [pscustomobject]@{ Name = 'memory'; Url = 'https://github.com/MSXOrg/memory.git'; Changes = 'push to main' } diff --git a/bootstrap/README.md b/bootstrap/README.md index 3e98acf..c838521 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -4,7 +4,7 @@ The single starting point for agents: a git-isolated local clone of the MSX cent ## Contents -- `Initialize-MsxWorkspace.ps1` — idempotent setup. Clones `MSXOrg/docs` and `MSXOrg/memory` under `~/.msx`, fast-forwards them if present, and writes a repository-local git identity so the workspace never modifies the global git config. +- `Initialize-MsxWorkspace.ps1` — idempotent setup. Clones `MSXOrg/docs` and `MSXOrg/memory` under `~/.msx`, attempts to fast-forward them if present, and writes a repository-local git identity so the workspace never modifies the global git config. - `AGENTS.template.md` — the user-global entry instruction. It bootstraps the workspace, then points the agent at the docs and memory. Install it once per machine (below). ## The model @@ -20,6 +20,9 @@ Run the bootstrap: ```powershell $docs = Join-Path $HOME '.msx/docs' +if ((Test-Path $docs) -and -not (Test-Path (Join-Path $docs '.git'))) { + throw "$docs exists but is not a git repository. Remove it and re-run." +} if (-not (Test-Path (Join-Path $docs '.git'))) { New-Item -ItemType Directory -Force -Path (Split-Path -Parent $docs) | Out-Null git clone https://github.com/MSXOrg/docs.git $docs diff --git a/src/docs/Ways-of-Working/Agentic-Development.md b/src/docs/Ways-of-Working/Agentic-Development.md index 1842933..6a17ea8 100644 --- a/src/docs/Ways-of-Working/Agentic-Development.md +++ b/src/docs/Ways-of-Working/Agentic-Development.md @@ -77,7 +77,7 @@ Process knowledge is never added to a distributed config file. If an agent needs ## The workspace bootstrap -The natively-read entry file is a thin **bootstrap**, not a copy of the docs. Each runtime auto-loads its own file — Copilot reads `AGENTS.md`, Claude Code reads `CLAUDE.md` (which imports the same instructions) — and that file's first instruction is to make the central workspace present locally, then read from it. +The **user-global** entry file is a thin **bootstrap**, not a copy of the docs. Each runtime auto-loads its own user-level file — Copilot from its user instructions, Claude Code from `~/.claude/CLAUDE.md` (which imports the same instructions) — and its first instruction is to make the central workspace present locally, then read from it. This is distinct from the per-repository `AGENTS.md` and `CLAUDE.md`, which remain thin pointers to the central descriptions. The workspace is a git-isolated clone of the central repositories under `~/.msx`: From 128ab715c0ad24b38911c290f3dbaa650c42526a Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 9 Jul 2026 14:53:34 +0200 Subject: [PATCH 11/16] Warn when any part of the default identity is in effect Copilot review round 9 on #31: the identity warning now fires when either -UserName or -UserEmail is not explicitly provided, not just -UserEmail. --- bootstrap/Initialize-MsxWorkspace.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap/Initialize-MsxWorkspace.ps1 b/bootstrap/Initialize-MsxWorkspace.ps1 index aed04a5..27ad534 100644 --- a/bootstrap/Initialize-MsxWorkspace.ps1 +++ b/bootstrap/Initialize-MsxWorkspace.ps1 @@ -58,8 +58,8 @@ param( Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' -if (-not $PSBoundParameters.ContainsKey('UserEmail')) { - Write-Warning "Using the default maintainer identity ($UserName <$UserEmail>). Pass -UserName / -UserEmail to attribute your own commits (memory pushes to main)." +if ((-not $PSBoundParameters.ContainsKey('UserName')) -or (-not $PSBoundParameters.ContainsKey('UserEmail'))) { + Write-Warning "Using part of the default maintainer identity ($UserName <$UserEmail>). Pass both -UserName and -UserEmail to attribute your own commits (memory pushes to main)." } $repositories = @( From 77f3bedee059dee2509626b112084b7a6d94e039 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 9 Jul 2026 15:00:02 +0200 Subject: [PATCH 12/16] Keep AGENTS.md a pure pointer; install bootstrap at user level only Copilot review round 10 on #31: drop the restated linter rule from the root AGENTS.md 'Start here'; steer the bootstrap template to user-level Copilot instructions only, keeping per-repo AGENTS.md a thin pointer. --- AGENTS.md | 2 +- bootstrap/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 858e19b..505539b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,7 +6,7 @@ This repository is the central documentation for the MSX ecosystem. Everything a 1. Read this file, then the [README](README.md) for what this repository is and how it builds. 2. Read the [Ways of Working](https://msxorg.github.io/docs/Ways-of-Working/) — how work flows from idea to delivery. -3. Load the [Coding Standards](https://msxorg.github.io/docs/Coding-Standards/) relevant to the change. Repo-local linter config wins where it disagrees. +3. Load the [Coding Standards](https://msxorg.github.io/docs/Coding-Standards/) relevant to the change. ## Roles diff --git a/bootstrap/README.md b/bootstrap/README.md index c838521..b688e1c 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -38,7 +38,7 @@ Wire it into the tools so it runs as the first instruction: @~/.msx/docs/bootstrap/AGENTS.template.md ``` -- **Copilot** reads `AGENTS.md` natively. Use the contents of `AGENTS.template.md` as your user-level Copilot instructions, or copy it into a repository as `AGENTS.md`. +- **Copilot** reads `AGENTS.md` natively. Install the contents of `AGENTS.template.md` as your **user-level** Copilot instructions so it applies in every repository. Per-repository `AGENTS.md` files stay thin pointers to the central docs — don't put the bootstrap there. ## Identity From 78fd4f850d00ee8d3ebf4f9180fb3c6e0ce798b8 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 9 Jul 2026 15:06:16 +0200 Subject: [PATCH 13/16] Check git config exit codes; document that MSXOrg/memory is private Copilot review round 11 on #31: check \0 after the two git config writes (consistent with the other git calls); note the private MSXOrg/memory prerequisite in the README and the template. --- bootstrap/AGENTS.template.md | 2 ++ bootstrap/Initialize-MsxWorkspace.ps1 | 2 ++ bootstrap/README.md | 2 ++ 3 files changed, 6 insertions(+) diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md index aec1bc6..9a8eb4a 100644 --- a/bootstrap/AGENTS.template.md +++ b/bootstrap/AGENTS.template.md @@ -25,6 +25,8 @@ This produces: Each clone has repository-local git config only; it never modifies the global git config or the repository being worked in (git still reads them, but only repository-local config is written). +> `MSXOrg/memory` is private — the bootstrap needs access to it (and working github.com credentials) for the memory clone. + ## Then — read before acting 1. Read the relevant pages under `~/.msx/docs` for the task at hand. diff --git a/bootstrap/Initialize-MsxWorkspace.ps1 b/bootstrap/Initialize-MsxWorkspace.ps1 index 27ad534..f9a32ad 100644 --- a/bootstrap/Initialize-MsxWorkspace.ps1 +++ b/bootstrap/Initialize-MsxWorkspace.ps1 @@ -95,7 +95,9 @@ $results = foreach ($repo in $repositories) { # Isolated identity: write repository-local config only. Git still reads # global and system config; the script never writes to them. git -C $path config user.name $UserName + if ($LASTEXITCODE -ne 0) { throw "git config user.name failed for '$path' (exit $LASTEXITCODE)." } git -C $path config user.email $UserEmail + if ($LASTEXITCODE -ne 0) { throw "git config user.email failed for '$path' (exit $LASTEXITCODE)." } [pscustomobject]@{ Repository = $repo.Name; Path = $path; Changes = $repo.Changes } } diff --git a/bootstrap/README.md b/bootstrap/README.md index b688e1c..96e9bdb 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -12,6 +12,8 @@ The single starting point for agents: a git-isolated local clone of the MSX cent - `~/.msx/docs` is **read context** — the ways of working, coding standards, and agent roles. Changes to it go through **pull requests**. - `~/.msx/memory` is **append-only context** — durable notes and session history. Changes to it are **pushed to main**. +> **Prerequisite:** `MSXOrg/memory` is a private repository — the bootstrap needs access to it (and working github.com credentials) to clone or update memory. + Keeping the workspace separate and git-isolated means an agent reads the same docs and memory in every repository, and its commits there use the workspace identity rather than whatever the working repository or the global config happens to be set to. ## Install (once per machine) From 5f2fa25f2e23c159e4e2e5be3924dd1f00adabb3 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 9 Jul 2026 15:42:12 +0200 Subject: [PATCH 14/16] Point CLAUDE.md and copilot-instructions.md silently at AGENTS.md Reduce both files to bare pointers so agents follow AGENTS.md without extra prose that could distract or conflict. Add the Copilot instructions under .github so Copilot picks them up natively. --- .github/copilot-instructions.md | 1 + CLAUDE.md | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..3884664 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1 @@ +Follow the instructions in [AGENTS.md](../AGENTS.md). diff --git a/CLAUDE.md b/CLAUDE.md index 23ade99..43c994c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,5 +1 @@ -# CLAUDE.md - @AGENTS.md - -Claude Code does not read `AGENTS.md` automatically, so this file imports it — the line above pulls in the shared instructions every agent follows. Keep any Claude-specific notes below the import; everything else lives in [AGENTS.md](AGENTS.md) and the documentation it points to. From 4672fe60d03764b0aaee5b86d8e149fae045893d Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 9 Jul 2026 15:42:12 +0200 Subject: [PATCH 15/16] Apply the PowerShell coding standard to Initialize-MsxWorkspace.ps1 Document parameters inline instead of .PARAMETER, add .OUTPUTS, gate state-changing operations with SupportsShouldProcess/ShouldProcess (matching Wait-CopilotReview.ps1), and emit result objects instead of Format-Table plus a status string. --- bootstrap/Initialize-MsxWorkspace.ps1 | 62 ++++++++++++++------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/bootstrap/Initialize-MsxWorkspace.ps1 b/bootstrap/Initialize-MsxWorkspace.ps1 index f9a32ad..bac9091 100644 --- a/bootstrap/Initialize-MsxWorkspace.ps1 +++ b/bootstrap/Initialize-MsxWorkspace.ps1 @@ -26,15 +26,6 @@ fast-forward what is already present, leaving a repository unchanged (with a warning) when it cannot fast-forward. -.PARAMETER Root - The workspace root under which 'docs' and 'memory' are placed. Defaults to ~/.msx. - -.PARAMETER UserName - The git author name written to each clone's local config. - -.PARAMETER UserEmail - The git author email written to each clone's local config. - .EXAMPLE ./Initialize-MsxWorkspace.ps1 Clones missing repositories and attempts to fast-forward existing ones under ~/.msx. @@ -42,15 +33,21 @@ .EXAMPLE ./Initialize-MsxWorkspace.ps1 -Root /work/.msx -Verbose Uses a custom workspace root and logs each step. + +.OUTPUTS + [pscustomobject] with Repository, Path, and Changes for each workspace repository. #> -[CmdletBinding()] +[CmdletBinding(SupportsShouldProcess)] param( + # The workspace root under which 'docs' and 'memory' are placed. [Parameter()] [string] $Root = (Join-Path $HOME '.msx'), + # The git author name written to each clone's local config. [Parameter()] [string] $UserName = 'Marius Storhaug', + # The git author email written to each clone's local config. [Parameter()] [string] $UserEmail = 'MariusStorhaug@users.noreply.github.com' ) @@ -67,40 +64,47 @@ $repositories = @( [pscustomobject]@{ Name = 'memory'; Url = 'https://github.com/MSXOrg/memory.git'; Changes = 'push to main' } ) -New-Item -ItemType Directory -Force -Path $Root | Out-Null +if ($PSCmdlet.ShouldProcess($Root, 'Create workspace root')) { + New-Item -ItemType Directory -Force -Path $Root | Out-Null +} $results = foreach ($repo in $repositories) { $path = Join-Path $Root $repo.Name if (Test-Path (Join-Path $path '.git')) { - Write-Verbose "Updating $path" - git -C $path fetch origin --quiet - if ($LASTEXITCODE -ne 0) { - throw "git fetch failed for '$path' (exit $LASTEXITCODE). Check network access and credentials for $($repo.Url)." - } - git -C $path pull --ff-only --quiet - if ($LASTEXITCODE -ne 0) { - Write-Warning "Could not fast-forward '$path' (local changes or diverged history). Left as-is." + if ($PSCmdlet.ShouldProcess($path, 'Fetch and fast-forward')) { + Write-Verbose "Updating $path" + git -C $path fetch origin --quiet + if ($LASTEXITCODE -ne 0) { + throw "git fetch failed for '$path' (exit $LASTEXITCODE). Check network access and credentials for $($repo.Url)." + } + git -C $path pull --ff-only --quiet + if ($LASTEXITCODE -ne 0) { + Write-Warning "Could not fast-forward '$path' (local changes or diverged history). Left as-is." + } } } else { if (Test-Path $path) { throw "Cannot clone into '$path': it exists but is not a git repository. Remove it or choose a different -Root." } - Write-Verbose "Cloning $($repo.Url) into $path" - git clone --quiet $repo.Url $path - if ($LASTEXITCODE -ne 0) { - throw "git clone failed for $($repo.Url) (exit $LASTEXITCODE). Check access and credentials (MSXOrg/memory is private)." + if ($PSCmdlet.ShouldProcess($repo.Url, "Clone into '$path'")) { + Write-Verbose "Cloning $($repo.Url) into $path" + git clone --quiet $repo.Url $path + if ($LASTEXITCODE -ne 0) { + throw "git clone failed for $($repo.Url) (exit $LASTEXITCODE). Check access and credentials (MSXOrg/memory is private)." + } } } # Isolated identity: write repository-local config only. Git still reads # global and system config; the script never writes to them. - git -C $path config user.name $UserName - if ($LASTEXITCODE -ne 0) { throw "git config user.name failed for '$path' (exit $LASTEXITCODE)." } - git -C $path config user.email $UserEmail - if ($LASTEXITCODE -ne 0) { throw "git config user.email failed for '$path' (exit $LASTEXITCODE)." } + if ($PSCmdlet.ShouldProcess($path, 'Set repository-local git identity')) { + git -C $path config user.name $UserName + if ($LASTEXITCODE -ne 0) { throw "git config user.name failed for '$path' (exit $LASTEXITCODE)." } + git -C $path config user.email $UserEmail + if ($LASTEXITCODE -ne 0) { throw "git config user.email failed for '$path' (exit $LASTEXITCODE)." } + } [pscustomobject]@{ Repository = $repo.Name; Path = $path; Changes = $repo.Changes } } -$results | Format-Table -AutoSize -Write-Output 'MSX workspace ready. Read docs and memory here; docs change through pull requests, memory pushes to main.' +$results From ee5ecaf56dd079b750255e6959d53a98a90f641d Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 9 Jul 2026 15:48:51 +0200 Subject: [PATCH 16/16] Fail fast on failed clones and reject empty identity overrides Install snippets (README + AGENTS.template) now check \0 after git clone and throw a clear error, so a failed first-time clone fails diagnostically instead of running the script from a missing path. Initialize-MsxWorkspace.ps1 adds ValidateNotNullOrEmpty to -Root, -UserName, and -UserEmail so accidental empty overrides fail early. Addresses Copilot review on PR #31. --- bootstrap/AGENTS.template.md | 3 +++ bootstrap/Initialize-MsxWorkspace.ps1 | 3 +++ bootstrap/README.md | 3 +++ 3 files changed, 9 insertions(+) diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md index 9a8eb4a..13f7014 100644 --- a/bootstrap/AGENTS.template.md +++ b/bootstrap/AGENTS.template.md @@ -14,6 +14,9 @@ if ((Test-Path $docs) -and -not (Test-Path (Join-Path $docs '.git'))) { if (-not (Test-Path (Join-Path $docs '.git'))) { New-Item -ItemType Directory -Force -Path (Split-Path -Parent $docs) | Out-Null git clone https://github.com/MSXOrg/docs.git $docs + if ($LASTEXITCODE -ne 0) { + throw "git clone of MSXOrg/docs failed (exit $LASTEXITCODE). Check network access and github.com credentials, then re-run." + } } pwsh (Join-Path $docs 'bootstrap/Initialize-MsxWorkspace.ps1') ``` diff --git a/bootstrap/Initialize-MsxWorkspace.ps1 b/bootstrap/Initialize-MsxWorkspace.ps1 index bac9091..ad644d8 100644 --- a/bootstrap/Initialize-MsxWorkspace.ps1 +++ b/bootstrap/Initialize-MsxWorkspace.ps1 @@ -41,14 +41,17 @@ param( # The workspace root under which 'docs' and 'memory' are placed. [Parameter()] + [ValidateNotNullOrEmpty()] [string] $Root = (Join-Path $HOME '.msx'), # The git author name written to each clone's local config. [Parameter()] + [ValidateNotNullOrEmpty()] [string] $UserName = 'Marius Storhaug', # The git author email written to each clone's local config. [Parameter()] + [ValidateNotNullOrEmpty()] [string] $UserEmail = 'MariusStorhaug@users.noreply.github.com' ) diff --git a/bootstrap/README.md b/bootstrap/README.md index 96e9bdb..ad93387 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -28,6 +28,9 @@ if ((Test-Path $docs) -and -not (Test-Path (Join-Path $docs '.git'))) { if (-not (Test-Path (Join-Path $docs '.git'))) { New-Item -ItemType Directory -Force -Path (Split-Path -Parent $docs) | Out-Null git clone https://github.com/MSXOrg/docs.git $docs + if ($LASTEXITCODE -ne 0) { + throw "git clone of MSXOrg/docs failed (exit $LASTEXITCODE). Check network access and github.com credentials, then re-run." + } } pwsh (Join-Path $docs 'bootstrap/Initialize-MsxWorkspace.ps1') ```