From aa13e84829bbeb33c45d724ae335ef744299ea28 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 29 Aug 2026 13:08:38 +0200 Subject: [PATCH 01/23] Centralize community file defaults --- CONTRIBUTING.md => .github/CONTRIBUTING.md | 2 +- AGENTS.md | 2 +- bootstrap/AGENTS.template.md | 4 +- .../agentic-development/design.md | 8 ++-- .../Ways-of-Working/Organization-Standard.md | 41 ++++++++++++++++--- .../Ways-of-Working/Repository-Standard.md | 26 ++++++++---- .../Workflow-Stages/Maintain-Guidance.md | 2 +- 7 files changed, 62 insertions(+), 23 deletions(-) rename CONTRIBUTING.md => .github/CONTRIBUTING.md (99%) diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 99% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md index 4a65770..a25866e 100644 --- a/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,4 +1,4 @@ -# Contributing +# Contributing to MSX Docs Every change lands through a pull request — nothing goes directly to `main`. See the [Contribution Workflow](https://msxorg.github.io/docs/Ways-of-Working/Contribution-Workflow/) diff --git a/AGENTS.md b/AGENTS.md index 515f062..35fb9d0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,7 +3,7 @@ This repository is `github.com/MSXOrg/docs`. Read in this order: 1. [README.md](README.md) — what this repository is, how it is laid out, and how it builds. -2. [CONTRIBUTING.md](CONTRIBUTING.md) — how a change is made and reviewed here. +2. [.github/CONTRIBUTING.md](.github/CONTRIBUTING.md) — how a change is made and reviewed here. 3. [src/docs/index.md](src/docs/index.md) — the documentation this repository owns. Follow the index inward. 4. `~/.msx/memory/index.md` — durable lessons from earlier work, read last. diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md index 97c923e..2c58160 100644 --- a/bootstrap/AGENTS.template.md +++ b/bootstrap/AGENTS.template.md @@ -164,7 +164,7 @@ Read `Ways-of-Working/Session-Interactions.md` in the canonical docs for what ea ## Work in the selected repository 1. Read its `README.md` to understand the repository and its build. -2. Read its `CONTRIBUTING.md` for the contribution and review contract. +2. Read its `.github/CONTRIBUTING.md` for the contribution and review contract. 3. Use a dedicated worktree and the branch naming defined by the canonical Ways of Working. 4. Make small, descriptive micro-commits and push every commit so remote state, CI, and the draft pull request stay current. 5. Capture verified reusable lessons in organization memory, following that repository's own instructions. @@ -172,4 +172,4 @@ Read `Ways-of-Working/Session-Interactions.md` in the canonical docs for what ea ## Two write rules - **Docs change through topic worktrees and pull requests.** Create a topic worktree from `~/.msx/docs.git`; never branch or work inside the canonical `~/.msx/docs` main worktree. -- **Memory follows repository policy.** Read the selected memory repository's `AGENTS.md` and `CONTRIBUTING.md` before writing. +- **Memory follows repository policy.** Read the selected memory repository's `AGENTS.md` and `CONTRIBUTING.md` before writing. Memory repositories retain the documented root-level contribution-guide exception. diff --git a/src/docs/Capabilities/agentic-development/design.md b/src/docs/Capabilities/agentic-development/design.md index 618faa5..c0a1391 100644 --- a/src/docs/Capabilities/agentic-development/design.md +++ b/src/docs/Capabilities/agentic-development/design.md @@ -65,15 +65,15 @@ Product repositories carry local context and thin pointers: .claude/ CLAUDE.md # required: routes Claude Code — @../AGENTS.md .github/ + CONTRIBUTING.md # how a change is made here copilot-instructions.md # required: routes the Copilot surfaces that need it instructions/ .instructions.md # exceptional: a path-scoped local caveat README.md # what it is, how it builds - CONTRIBUTING.md # how a change is made here docs/ # architecture and domain context ``` -The repository owns only repository-specific nuance, and each kind has a file that owns it: `README.md` for what the repository is and how it builds, `CONTRIBUTING.md` for contribution mechanics, `docs/` for architecture and domain context, and path-scoped rule files for local caveats. `AGENTS.md` points at them and holds none of it. Cross-cutting standards remain in `docs`; reusable lessons remain in `memory`. Thin means "no duplicated reusable process," not "discard the local operating contract" — the contract lives, it just lives in the file a human would read. +The repository owns only repository-specific nuance, and each kind has a file that owns it: `README.md` for what the repository is and how it builds, `.github/CONTRIBUTING.md` for contribution mechanics, `docs/` for architecture and domain context, and path-scoped rule files for local caveats. `AGENTS.md` points at them and holds none of it. Cross-cutting standards remain in `docs`; reusable lessons remain in `memory`. Thin means "no duplicated reusable process," not "discard the local operating contract" — the contract lives, it just lives in the file a human would read. ## OKF page model @@ -172,7 +172,7 @@ Resolution is deterministic. If the active repository remote is `github.com/PSMo This repository is `github.com/MSXOrg/`. Read in this order: 1. `README.md` — what this repository is and how it builds. -2. `CONTRIBUTING.md` — how a change is made and reviewed here. +2. `.github/CONTRIBUTING.md` — how a change is made and reviewed here. 3. `docs/index.md` — this repository's own documentation. 4. `~/.msx/docs/src/docs/index.md` — the organization standards. 5. `~/.msx/memory/index.md` — durable lessons, read last. @@ -203,7 +203,7 @@ Follow the instructions in [AGENTS.md](../AGENTS.md). That is the entire file. It holds no reading order, no workflow, and no standard, so there is nothing in it that can fall out of step with the router. Any future runtime is handled the same way: give it a route under whatever filename it reads, and leave the content in `AGENTS.md`. -Path-scoped instruction files are reserved for local rules that cannot live centrally because they apply only to a repository path, and only when the rule does not belong in `README.md` or `CONTRIBUTING.md` instead. They never define workflow stages. +Path-scoped instruction files are reserved for local rules that cannot live centrally because they apply only to a repository path, and only when the rule does not belong in `README.md` or `.github/CONTRIBUTING.md` instead. They never define workflow stages. ## Local workspace diff --git a/src/docs/Ways-of-Working/Organization-Standard.md b/src/docs/Ways-of-Working/Organization-Standard.md index 822650d..20fd12e 100644 --- a/src/docs/Ways-of-Working/Organization-Standard.md +++ b/src/docs/Ways-of-Working/Organization-Standard.md @@ -31,7 +31,7 @@ Every initiative organization must define standards for these shared file famili | File family | Standard owns | | --- | --- | -| Community health files | Code of conduct, contribution guide, support policy, security policy, and license expectations. | +| Community health files | Central code of conduct, contribution guide, support policy, security policy, and pull request template defaults. | | Repository context | README defaults, documentation ownership, and repository metadata expectations. | | Review workflow | Pull request template, review routing, CODEOWNERS, namespace-qualified automation label sets, and change-type conventions. | | Supply chain | Dependabot configuration, namespace-qualified dependency update labels, security update behavior, and review expectations. | @@ -41,11 +41,37 @@ Every initiative organization must define standards for these shared file famili These standards must be written down before broad alignment work starts. File alignment without a written standard only spreads local preference faster. -## Repository-local files are the enforceable surface +## Community files are organization defaults -GitHub's special organization `.github` repository can provide fallback community files, but it is not the MSX enforcement model. Repository-local files are still required because they are what humans, agents, linters, Dependabot, CODEOWNERS, release workflows, and pull requests actually read and review. +Community policies are organization-wide commitments, not repository-specific +configuration. Each initiative organization MUST provide its code of conduct, +security policy, support policy, and pull request template as defaults in its +special `.github` repository. These defaults apply whenever a repository does +not need a documented local exception. -Use organization-level `.github` fallbacks only as a convenience, never as the only copy of a required standard file. +Store every organization community default under the `.github/` directory of +the special `.github` repository: + +| File | Purpose | +| --- | --- | +| `.github/CODE_OF_CONDUCT.md` | Defines expected community behaviour. | +| `.github/SECURITY.md` | Defines supported versions and private vulnerability reporting. | +| `.github/SUPPORT.md` | Defines where users ask for help. | +| `.github/pull_request_template.md` | Scaffolds pull requests in the organization's required format. | + +A repository MAY carry a local copy only when it needs a material, +repository-specific exception. The local copy takes precedence, so the +exception and its owner MUST be documented in the initiative guidance. + +## Repository-local context is the enforceable surface + +Every repository still carries the context that cannot be inferred from an +organization default: its `README.md`, `.github/CONTRIBUTING.md`, and +`AGENTS.md` with its client routes. The contribution guide tells humans and +agents how the organization defaults apply and where the central pull request +template lives. Automation configuration, ownership, and repository-specific +legal terms also remain repository-local where the +[Repository Standard](Repository-Standard.md) requires them. ## Managed files @@ -74,7 +100,12 @@ Organizations must distinguish mandatory files from optional or type-specific fi | Type-specific | Files that apply only to a repository type, such as a PowerShell module, GitHub Action, Terraform module, or docs repo. | | Repository-specific | Local files that are intentionally owned by one repository and not managed centrally. | -Security, contribution, conduct, support, dependency update, and license files are candidates for mandatory file sets. Linter settings, agent instructions, and workflow defaults may be global or type-specific depending on the initiative. +Repository-local context, dependency updates, ownership, license terms, and +type-specific files are candidates for mandatory file sets. Organization +community defaults are mandatory at the organization level; repositories use +them through GitHub's fallback unless they have a documented exception. Linter +settings, agent instructions, and workflow defaults may be global or +type-specific depending on the initiative. Which set applies to a repository is derived from its classification rather than decided per repository, so that adding a repository requires classifying it and nothing else. The classification mechanism, the per-type required-file matrix, and the composition rules for a repository that is more than one type are defined by [Repository Governance](../Capabilities/repository-governance/spec.md). diff --git a/src/docs/Ways-of-Working/Repository-Standard.md b/src/docs/Ways-of-Working/Repository-Standard.md index c8305a8..009e50f 100644 --- a/src/docs/Ways-of-Working/Repository-Standard.md +++ b/src/docs/Ways-of-Working/Repository-Standard.md @@ -25,17 +25,18 @@ discoverability minimum defined below instead. | --- | --- | | `README.md` | Acts as the repository start page: purpose, value, access, first mental model, and where to go next. | | `LICENSE` | States the legal terms for reuse and redistribution. | -| `CONTRIBUTING.md` | Explains how to contribute or links to the initiative contribution guide. | -| `SECURITY.md` | Explains supported versions and private vulnerability reporting. | -| `SUPPORT.md` | Explains where users ask for help. | -| `CODE_OF_CONDUCT.md` | Defines expected community behaviour. | +| `.github/CONTRIBUTING.md` | Explains how to contribute, including how the organization defaults and central pull request template apply. | | `AGENTS.md` and its client routes | Route every agent runtime from this repository's own files outward to the initiative and central documentation, then to memory. [Agentic Development](../Capabilities/agentic-development/design.md#client-behavior) names the files and the path each one sits at. | | `.github/dependabot.yml` | Configures platform-native dependency-update pull requests for supported ecosystems. The `github-actions` ecosystem is expected in virtually every repository; an unsupported ecosystem follows the centrally managed exception path rather than a repository-local updater. | | `.github/CODEOWNERS` | Routes reviews to responsible owners. | -| `.github/pull_request_template.md` | Scaffolds pull requests in the MSX [PR Format](PR-Format.md) (PR Manager) style — an icon + change-type + user-facing-outcome title, user-facing description sections, an optional technical-details block, and a related-issues block. | | `.gitattributes` | Normalizes line endings and declares text/binary handling so the repository can be developed and built consistently on Linux, macOS, and Windows. | | `.gitignore` | Ignores files that must never be committed, tailored to the repository's ecosystem: operating-system files, editor and developer-tooling files, language and test-harness artifacts, and all local build outputs and files created during build and test. | +The organization provides `CODE_OF_CONDUCT.md`, `SECURITY.md`, `SUPPORT.md`, +and `.github/pull_request_template.md` as GitHub community defaults. Do not +copy them into a repository unless it needs a documented local exception; see +[Organization Standard](Organization-Standard.md#community-files-are-organization-defaults). + Repository types may require additional files. For example, a PowerShell module may require `.github/PSModule.yml`, while a GitHub Action may require `action.yml`. ### Required files by type @@ -53,7 +54,7 @@ stated below, not for the governed baseline. | **Infrastructure** | Documentation of each environment the repository deploys to and how a change reaches it, plus the promotion automation the [promotion flow](../Capabilities/repository-governance/design-types.md#infrastructure) requires. | | **Docs** | The documentation source root and the build configuration the documentation-build check runs. | | **Memory** | The structure documented by the [memory repository template](../Capabilities/agentic-development/memory-template.md). | -| **Unmanaged** | Nothing — but the exemption does not extend to discoverability: `README.md`, `SECURITY.md`, and the agent router remain required, because a repository nobody governs is still a repository someone will open. | +| **Unmanaged** | Nothing — but the exemption does not extend to discoverability: `README.md`, `.github/CONTRIBUTING.md`, and the agent router remain required, because a repository nobody governs is still a repository someone will open. | The set a governed repository is audited against is the mandatory set plus the additions of every type it declares; an Unmanaged repository is audited only @@ -77,7 +78,11 @@ A README answers these questions, in this order: | How does it work? | Give a concise introduction to the main capability or operating model. | | How do I get more info? | Point to the documentation surface that owns the details. | -Do not use the README as a community-file index. Assume readers can find standard repository files such as `LICENSE`, `CONTRIBUTING.md`, `SECURITY.md`, and `CODE_OF_CONDUCT.md` through GitHub's UI and repository conventions. The README should mention them only when the repository has an unusual rule that readers must know before using the product. +Do not use the README as a community-file index. Assume readers can find the +organization's standard community defaults and repository-local files such as +`LICENSE` and `.github/CONTRIBUTING.md` through GitHub's UI and repository +conventions. The README should mention them only when the repository has an +unusual rule that readers must know before using the product. Do not repeat repository-sidebar information in prose. If GitHub already exposes the repository description, deployments, releases, or site URL, the README may rely on those surfaces unless the information is necessary to answer the start-page questions. @@ -95,7 +100,7 @@ Default expectations by repository type: | Libraries, services, CLIs, and applications | Product docs live under `docs/` and are published when the product needs more than a small README. | | GitHub Actions | The README is the main documentation surface because GitHub Actions users expect inputs, outputs, permissions, and examples next to `action.yml`. | | Reusable workflows | The README is the main documentation surface because callers need workflow interface, permissions, secrets, and examples in the repository. | -| Documentation repositories | The published site is the product. The repository README explains what the source repository is and how it is laid out, and points to `CONTRIBUTING.md` for the authoring conventions and the local build. | +| Documentation repositories | The published site is the product. The repository README explains what the source repository is and how it is laid out, and points to `.github/CONTRIBUTING.md` for the authoring conventions and the local build. | Documentation content lives in one folder, never spread across the repository root. A repository whose product is content — a documentation site, a reference collection, an archive of external material — keeps that content under a single documentation root: `docs/` by default, or a generator's source root such as `src/docs/` when the site tooling needs one. The repository root stays reserved for the README, the tooling, and the governance files, so a reader can tell content from machinery without opening a folder. @@ -165,7 +170,10 @@ Default title pattern: The description should lead with user-facing impact, continue with user-facing change sections, include optional technical details after those sections, and end with the related-issues block. It closes one scoped Task or Bug as required by [PR Format](PR-Format.md), with any additional closing links limited to issues the session-end convergence sweep shows are fully delivered by the same diff. -Repository templates may be simpler than the full PR Manager body, but they must gather enough information to reconstruct it. +The organization-level `.github` repository supplies the default template. +The repository-local contribution guide directs humans and agents to the +organization template and its required format. A repository carries a local +template only for a documented exception. ## Managed files diff --git a/src/docs/Ways-of-Working/Workflow-Stages/Maintain-Guidance.md b/src/docs/Ways-of-Working/Workflow-Stages/Maintain-Guidance.md index efab598..4c820d9 100644 --- a/src/docs/Ways-of-Working/Workflow-Stages/Maintain-Guidance.md +++ b/src/docs/Ways-of-Working/Workflow-Stages/Maintain-Guidance.md @@ -29,7 +29,7 @@ Write the stage as a page in this section, following the shape of its siblings: ### 3. Keep pointers thin -A repository never carries a copy of the workflow. Its `AGENTS.md` — with the client routes that reach it — lists these pages as a destination and nothing more. Repository-specific nuance lives in `README.md`, `CONTRIBUTING.md`, and the repository's own `docs/`; the router points at those files rather than restating them. When a new runtime is adopted, add a route under the filename it reads; do not move process knowledge into it. See [Agentic Development](../../Capabilities/agentic-development/design.md#client-behavior). +A repository never carries a copy of the workflow. Its `AGENTS.md` — with the client routes that reach it — lists these pages as a destination and nothing more. Repository-specific nuance lives in `README.md`, `.github/CONTRIBUTING.md`, and the repository's own `docs/`; the router points at those files rather than restating them. When a new runtime is adopted, add a route under the filename it reads; do not move process knowledge into it. See [Agentic Development](../../Capabilities/agentic-development/design.md#client-behavior). ### 4. Validate From 2cdee02864e498dd225c921ce2e37ea92f22798f Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 29 Aug 2026 13:21:30 +0200 Subject: [PATCH 02/23] Normalize contribution guide title --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a25866e..4a65770 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,4 +1,4 @@ -# Contributing to MSX Docs +# Contributing Every change lands through a pull request — nothing goes directly to `main`. See the [Contribution Workflow](https://msxorg.github.io/docs/Ways-of-Working/Contribution-Workflow/) From 712110b3e6217f22e517cb917a3d82d81ea2fedb Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 29 Aug 2026 13:22:44 +0200 Subject: [PATCH 03/23] Remove memory exception guidance --- bootstrap/AGENTS.template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md index 2c58160..960742e 100644 --- a/bootstrap/AGENTS.template.md +++ b/bootstrap/AGENTS.template.md @@ -172,4 +172,4 @@ Read `Ways-of-Working/Session-Interactions.md` in the canonical docs for what ea ## Two write rules - **Docs change through topic worktrees and pull requests.** Create a topic worktree from `~/.msx/docs.git`; never branch or work inside the canonical `~/.msx/docs` main worktree. -- **Memory follows repository policy.** Read the selected memory repository's `AGENTS.md` and `CONTRIBUTING.md` before writing. Memory repositories retain the documented root-level contribution-guide exception. +- **Memory follows repository policy.** Read the selected memory repository's `AGENTS.md` and `CONTRIBUTING.md` before writing. From a527c95ebc1f8e25df110a1728cd8cc4b3dd794b Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 08:41:34 +0200 Subject: [PATCH 04/23] Use organization-named context roots --- .github/CONTRIBUTING.md | 4 +-- AGENTS.md | 2 +- bootstrap/AGENTS.template.md | 18 ++++++------- bootstrap/Initialize-MsxWorkspace.ps1 | 10 +++---- bootstrap/README.md | 26 +++++++++---------- .../agentic-development/design.md | 20 +++++++------- src/docs/Ways-of-Working/Git-Worktrees.md | 2 +- 7 files changed, 42 insertions(+), 40 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 4a65770..81da516 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -115,11 +115,11 @@ current state of the work. ## Agent workspace -Agents working here read organization memory from `~/.msx/memory`, set up by the +Agents working here read organization memory from `~/.msxorg/memory`, set up by the [workspace bootstrap](bootstrap/README.md). That bootstrap is user-global: it is installed once per machine, not per repository. -When a verified lesson is likely to matter again, record it in `~/.msx/memory` and push it +When a verified lesson is likely to matter again, record it in `~/.msxorg/memory` and push it directly to `main`, following that repository's own contribution guide. See the [README](README.md) for what this repository is and how it is laid out, and the diff --git a/AGENTS.md b/AGENTS.md index 35fb9d0..330df4f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,7 +5,7 @@ This repository is `github.com/MSXOrg/docs`. Read in this order: 1. [README.md](README.md) — what this repository is, how it is laid out, and how it builds. 2. [.github/CONTRIBUTING.md](.github/CONTRIBUTING.md) — how a change is made and reviewed here. 3. [src/docs/index.md](src/docs/index.md) — the documentation this repository owns. Follow the index inward. -4. `~/.msx/memory/index.md` — durable lessons from earlier work, read last. +4. `~/.msxorg/memory/index.md` — durable lessons from earlier work, read last. Step 3 is also the MSX organization standard, so nothing governs this repository from above it. diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md index 960742e..29d65f9 100644 --- a/bootstrap/AGENTS.template.md +++ b/bootstrap/AGENTS.template.md @@ -8,10 +8,10 @@ Everything is a work in progress and can be updated and improved. Fix a small pr ## First — bootstrap the workspace -The workspace is a git-isolated clone of the central repositories under `~/.msx`. Set it up before reading context. Existing context repositories must be clean, on their default branch, and exactly synchronized with the remote: +The workspace is a git-isolated clone of the organization repositories under `~/.msxorg` by default. Set it up before reading context. Use a separate organization-named root, such as `~/.psmodule` for PSModule. Existing context repositories must be clean, on their default branch, and exactly synchronized with the remote: ```powershell -$workspaceRoot = if ($env:MSX_WORKSPACE_ROOT) { $env:MSX_WORKSPACE_ROOT } else { Join-Path $HOME '.msx' } +$workspaceRoot = if ($env:MSX_WORKSPACE_ROOT) { $env:MSX_WORKSPACE_ROOT } else { Join-Path $HOME '.msxorg' } $docsUrl = if ($env:MSX_DOCS_URL) { $env:MSX_DOCS_URL } else { 'https://github.com/MSXOrg/docs.git' } $memoryUrl = if ($env:MSX_MEMORY_URL) { $env:MSX_MEMORY_URL } else { 'https://github.com/MSXOrg/memory.git' } $docs = Join-Path $workspaceRoot 'docs' @@ -113,7 +113,7 @@ $projects = @( # Add project-specific entries when this template is adopted there: # @{ # Name = 'PSModule' - # Path = 'projects/PSModule' + # Path = '' # DocsUrl = 'https://github.com/PSModule/docs.git' # MemoryUrl = 'https://github.com/PSModule/memory.git' # } @@ -128,9 +128,9 @@ Keep the MSXOrg entry and add only the additional project coordinates required b This produces: -- `~/.msx/docs.git` — bare backing repository for central docs. -- `~/.msx/docs` — clean, readable main worktree containing ways of working, standards, and workflow guidance. -- `~/.msx/memory` — what has been learned before: durable notes and prior session context. +- `~/.msxorg/docs.git` — bare backing repository for central docs. +- `~/.msxorg/docs` — clean, readable main worktree containing ways of working, standards, and workflow guidance. +- `~/.msxorg/memory` — what has been learned before: durable notes and prior session context. 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). @@ -139,10 +139,10 @@ Each clone has repository-local git config only; it never modifies the global gi ## Then — read before acting 1. Segment the work by host, organization, repository, path, and task, so the right project context is selected before any of it is loaded. -2. Start at `~/.msx/docs/src/docs/index.md`. +2. Start at `~/.msxorg/docs/src/docs/index.md`. 3. Follow the Ways of Working index to `Workflow.md`. 4. Infer the current stage from the task and its artifacts, then read the linked stage procedure. -5. Read the relevant standards, repository context, and `~/.msx/memory`. +5. Read the relevant standards, repository context, and `~/.msxorg/memory`. In a repository, its root `AGENTS.md` names the host and organization and lists the order to read in. This file carries the bootstrap and the segmentation step; the repository file carries the route. Neither restates the other. @@ -171,5 +171,5 @@ Read `Ways-of-Working/Session-Interactions.md` in the canonical docs for what ea ## Two write rules -- **Docs change through topic worktrees and pull requests.** Create a topic worktree from `~/.msx/docs.git`; never branch or work inside the canonical `~/.msx/docs` main worktree. +- **Docs change through topic worktrees and pull requests.** Create a topic worktree from `~/.msxorg/docs.git`; never branch or work inside the canonical `~/.msxorg/docs` main worktree. - **Memory follows repository policy.** Read the selected memory repository's `AGENTS.md` and `CONTRIBUTING.md` before writing. diff --git a/bootstrap/Initialize-MsxWorkspace.ps1 b/bootstrap/Initialize-MsxWorkspace.ps1 index 80ddff9..7d1091d 100644 --- a/bootstrap/Initialize-MsxWorkspace.ps1 +++ b/bootstrap/Initialize-MsxWorkspace.ps1 @@ -28,17 +28,17 @@ .EXAMPLE ./Initialize-MsxWorkspace.ps1 - Clones missing repositories and exactly synchronizes existing ones under ~/.msx. + Clones missing repositories and exactly synchronizes existing ones under ~/.msxorg. .EXAMPLE - ./Initialize-MsxWorkspace.ps1 -Root /work/.msx -Verbose + ./Initialize-MsxWorkspace.ps1 -Root /work/.msxorg -Verbose Uses a custom workspace root and logs each step. .EXAMPLE $projects = @( @{ Name = 'PSModule' - Path = 'projects/PSModule' + Path = '' DocsUrl = 'https://github.com/PSModule/docs.git' MemoryUrl = 'https://github.com/PSModule/memory.git' } @@ -52,10 +52,10 @@ #> [CmdletBinding(SupportsShouldProcess)] param( - # The workspace root under which 'docs' and 'memory' are placed. + # The organization workspace root under which 'docs' and 'memory' are placed. [Parameter()] [ValidateNotNullOrEmpty()] - [string] $Root = (Join-Path $HOME '.msx'), + [string] $Root = (Join-Path $HOME '.msxorg'), # The git author name written to each clone's local config. [Parameter()] diff --git a/bootstrap/README.md b/bootstrap/README.md index 469d7a8..9a0562d 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -1,18 +1,18 @@ # 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. +The single starting point for agents: a git-isolated local clone of the MSXOrg repositories under `~/.msxorg`, plus the instruction that sends every agent there first. ## Contents -- `Initialize-MsxWorkspace.ps1` — idempotent setup. Clones `MSXOrg/docs` and `MSXOrg/memory` under `~/.msx`, requires existing clones to exactly match their remote default branches, 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 `~/.msxorg`, requires existing clones to exactly match their remote default branches, 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 -- `~/.msx/docs` is **read context** — the ways of working, coding standards, and agent workflow. Changes to it go through **pull requests**. -- `~/.msx/docs.git` is the bare backing repository for the readable, clean `~/.msx/docs` main worktree. -- `~/.msx/memory` is **durable context** — notes and session history governed by that repository's contribution policy. -- `~/.msx/projects//docs.git` and `docs/` provide the same bare+main-worktree model for optional project docs; `memory/` remains a simple checkout. +- `~/.msxorg/docs` is **read context** — the ways of working, coding standards, and agent workflow. Changes to it go through **pull requests**. +- `~/.msxorg/docs.git` is the bare backing repository for the readable, clean `~/.msxorg/docs` main worktree. +- `~/.msxorg/memory` is **durable context** — notes and session history governed by that repository's contribution policy. +- `~/./docs.git` and `docs/` provide the same bare+main-worktree model for optional organization docs; `memory/` remains a simple checkout. > **Prerequisite:** `MSXOrg/memory` is a private repository — the bootstrap needs access to it (and working github.com credentials) to clone or update memory. @@ -20,14 +20,14 @@ Before either repository is used, bootstrap fetches it and requires a clean chec 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. -The loaded `AGENTS.md` points to the roots; discovery happens in documentation. Start at `~/.msx/docs/src/docs/index.md`, follow Ways of Working to Workflow, infer the current stage, and read the linked procedure. Clear task language can shortcut stage selection, but no skill or instruction file owns a separate copy of the process. +The loaded `AGENTS.md` points to the roots; discovery happens in documentation. Start at `~/.msxorg/docs/src/docs/index.md`, follow Ways of Working to Workflow, infer the current stage, and read the linked procedure. Clear task language can shortcut stage selection, but no skill or instruction file owns a separate copy of the process. ## Install (once per machine) Run the bootstrap: ```powershell -$workspaceRoot = if ($env:MSX_WORKSPACE_ROOT) { $env:MSX_WORKSPACE_ROOT } else { Join-Path $HOME '.msx' } +$workspaceRoot = if ($env:MSX_WORKSPACE_ROOT) { $env:MSX_WORKSPACE_ROOT } else { Join-Path $HOME '.msxorg' } $docsUrl = if ($env:MSX_DOCS_URL) { $env:MSX_DOCS_URL } else { 'https://github.com/MSXOrg/docs.git' } $memoryUrl = if ($env:MSX_MEMORY_URL) { $env:MSX_MEMORY_URL } else { 'https://github.com/MSXOrg/memory.git' } $docs = Join-Path $workspaceRoot 'docs' @@ -147,26 +147,26 @@ $projects = @( } @{ Name = 'PSModule' - Path = 'projects/PSModule' + Path = '' DocsUrl = 'https://github.com/PSModule/docs.git' MemoryUrl = 'https://github.com/PSModule/memory.git' } ) -& (Join-Path $docs 'bootstrap/Initialize-MsxWorkspace.ps1') -Project $projects +& (Join-Path $docs 'bootstrap/Initialize-MsxWorkspace.ps1') -Root (Join-Path $HOME '.psmodule') -Project $projects ``` -Each plug-in uses the same fail-closed freshness validation. `Path` is relative to `~/.msx`, so projects can choose a collision-free location without forking the bootstrap. +Each plug-in uses the same fail-closed freshness validation. `Path` is relative to the organization workspace root, so projects can choose a collision-free location without forking the bootstrap. Run a separate workspace for each GitHub organization, such as `~/.psmodule` for PSModule. Existing clean simple docs clones are migrated automatically. The original clone is retained beside the new layout as `docs.simple-clone-backup` for manual verification and removal. Existing docs worktrees backed by another bare path are reused in place. Dirty, ahead, diverged, wrong-branch, conflicting-path, or otherwise unsafe layouts stop with actionable guidance before conversion. -Docs changes use topic worktrees created from `~/.msx/docs.git`; never branch or work inside the canonical `~/.msx/docs` main worktree. +Docs changes use topic worktrees created from `~/.msxorg/docs.git`; never branch or work inside the canonical `~/.msxorg/docs` main worktree. 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 + @~/.msxorg/docs/bootstrap/AGENTS.template.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. diff --git a/src/docs/Capabilities/agentic-development/design.md b/src/docs/Capabilities/agentic-development/design.md index c0a1391..54283a4 100644 --- a/src/docs/Capabilities/agentic-development/design.md +++ b/src/docs/Capabilities/agentic-development/design.md @@ -174,8 +174,8 @@ This repository is `github.com/MSXOrg/`. Read in this order: 1. `README.md` — what this repository is and how it builds. 2. `.github/CONTRIBUTING.md` — how a change is made and reviewed here. 3. `docs/index.md` — this repository's own documentation. -4. `~/.msx/docs/src/docs/index.md` — the organization standards. -5. `~/.msx/memory/index.md` — durable lessons, read last. +4. `~/.msxorg/docs/src/docs/index.md` — the organization standards. +5. `~/.msxorg/memory/index.md` — durable lessons, read last. Read nearest first. A local file never overrides a standard, and memory never overrides documentation. @@ -210,20 +210,22 @@ Path-scoped instruction files are reserved for local rules that cannot live cent A local bootstrap makes central context predictable: ```text -~/.msx/ +~/.msxorg/ docs.git/ # MSXOrg/docs bare backing repository docs/ # clean MSXOrg/docs main worktree memory/ # simple MSXOrg/memory checkout - projects/ - PSModule/ - docs.git/ # optional project docs backing repository - docs/ # optional project docs main worktree - memory/ # optional project memory checkout +~/.psmodule/ + docs.git/ # PSModule/docs bare backing repository + docs/ # PSModule/docs main worktree + memory/ # PSModule/memory checkout ``` The bootstrap clones missing repositories and fetches every existing context repository before use. Each clone must be clean, checked out on the remote default branch, and exactly equal to the fetched remote head. A dirty, locally ahead, diverged, wrong-branch, or unreachable clone stops context resolution; the agent does not use a possibly stale local copy. Bootstrap writes repository-local git configuration only. -MSXOrg is the default project. Additional projects plug in a name, relative workspace path, docs URL, and memory URL. For example, PSModule can use `projects/PSModule/{docs,memory}` beneath the same workspace while reusing the identical synchronization and validation path. Repository agent files retain this small coordinate block because it is required before project documentation can be reached; the reusable bootstrap behavior remains central. +Each GitHub organization has its own organization-named workspace root, such as +`~/.msxorg` for MSXOrg or `~/.psmodule` for PSModule. Repository agent files +retain the organization coordinates required before project documentation can be +reached; the reusable bootstrap behavior remains central. ## Refresh hooks diff --git a/src/docs/Ways-of-Working/Git-Worktrees.md b/src/docs/Ways-of-Working/Git-Worktrees.md index 9321c05..da5b0fd 100644 --- a/src/docs/Ways-of-Working/Git-Worktrees.md +++ b/src/docs/Ways-of-Working/Git-Worktrees.md @@ -42,7 +42,7 @@ In a single ordinary clone the opposite is forced: one branch checked out at a t - **`/`** — the canonical default-branch worktree. Kept clean and exactly synchronized for reading, diffing, and comparisons. Never directly committed to. - **`-/`** — one worktree folder per repository-delivery Task or Bug in flight, named by issue number and a short slug. The folder is a concise local path; its branch uses the required `/-` name, so the two names do not need to match. -For the central MSX context, this becomes `~/.msx/docs.git` plus the readable `~/.msx/docs` main worktree. Memory remains a simple checkout at `~/.msx/memory`. +For the central MSXOrg context, this becomes `~/.msxorg/docs.git` plus the readable `~/.msxorg/docs` main worktree. Memory remains a simple checkout at `~/.msxorg/memory`. Each GitHub organization uses its own organization-named root, such as `~/.psmodule` for PSModule. ## Remotes From 089017e65c07a38611b46cb690359beceb7897eb Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 08:50:16 +0200 Subject: [PATCH 05/23] Align agents file heading standard --- AGENTS.md | 2 +- src/docs/Capabilities/agentic-development/design.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 330df4f..d059a7c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,4 @@ -# Agent Instructions +# Agents This repository is `github.com/MSXOrg/docs`. Read in this order: diff --git a/src/docs/Capabilities/agentic-development/design.md b/src/docs/Capabilities/agentic-development/design.md index 54283a4..2ae31ab 100644 --- a/src/docs/Capabilities/agentic-development/design.md +++ b/src/docs/Capabilities/agentic-development/design.md @@ -167,7 +167,7 @@ Resolution is deterministic. If the active repository remote is `github.com/PSMo `AGENTS.md` is the cross-runtime router. It names the project and lists where to read, in order. It holds nothing else — no bootstrap, no build commands, no contribution mechanics, no standards. ```markdown -# Agent Instructions +# Agents This repository is `github.com/MSXOrg/`. Read in this order: From c2bfb63f2a5b4c0209bf119b454f12a165f3c1f1 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 08:55:17 +0200 Subject: [PATCH 06/23] Remove memory repository guidance --- .github/CONTRIBUTING.md | 9 - AGENTS.md | 3 +- bootstrap/AGENTS.template.md | 10 +- bootstrap/Initialize-MsxWorkspace.ps1 | 68 +- bootstrap/README.md | 23 +- .../agentic-development/conformance.md | 4 +- ...ment-architecture-and-memory-boundaries.md | 48 -- .../agentic-development/decisions/index.md | 8 +- .../agentic-development/design.md | 103 +-- .../Capabilities/agentic-development/index.md | 11 +- .../agentic-development/memory-template.md | 178 ---- .../Capabilities/agentic-development/spec.md | 59 +- src/docs/Capabilities/index.md | 2 +- .../repository-governance/design-types.md | 19 - .../Ways-of-Working/Documentation-Model.md | 3 +- src/docs/Ways-of-Working/Git-Worktrees.md | 2 +- .../Ways-of-Working/Repository-Standard.md | 3 +- .../Repository-Type-Property.md | 15 +- src/zensical.toml | 2 - tests/Initialize-MsxWorkspace.Tests.ps1 | 798 +----------------- 20 files changed, 114 insertions(+), 1254 deletions(-) delete mode 100644 src/docs/Capabilities/agentic-development/decisions/document-architecture-and-memory-boundaries.md delete mode 100644 src/docs/Capabilities/agentic-development/memory-template.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 81da516..959ba7b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -113,15 +113,6 @@ conventional-commit prefixes. See Push every commit, so the remote branch, CI, and the draft pull request always reflect the current state of the work. -## Agent workspace - -Agents working here read organization memory from `~/.msxorg/memory`, set up by the -[workspace bootstrap](bootstrap/README.md). That bootstrap is user-global: it is installed -once per machine, not per repository. - -When a verified lesson is likely to matter again, record it in `~/.msxorg/memory` and push it -directly to `main`, following that repository's own contribution guide. - See the [README](README.md) for what this repository is and how it is laid out, and the [Ways of Working](https://msxorg.github.io/docs/Ways-of-Working/) for the conventions every pull request follows — issue format, PR format, branching, and review etiquette. diff --git a/AGENTS.md b/AGENTS.md index d059a7c..8661b9e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,8 +5,7 @@ This repository is `github.com/MSXOrg/docs`. Read in this order: 1. [README.md](README.md) — what this repository is, how it is laid out, and how it builds. 2. [.github/CONTRIBUTING.md](.github/CONTRIBUTING.md) — how a change is made and reviewed here. 3. [src/docs/index.md](src/docs/index.md) — the documentation this repository owns. Follow the index inward. -4. `~/.msxorg/memory/index.md` — durable lessons from earlier work, read last. Step 3 is also the MSX organization standard, so nothing governs this repository from above it. -Read nearest first. A local file never overrides a standard, and memory never overrides documentation. +Read nearest first. A local file never overrides a standard. diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md index 29d65f9..1c5e65f 100644 --- a/bootstrap/AGENTS.template.md +++ b/bootstrap/AGENTS.template.md @@ -8,12 +8,11 @@ Everything is a work in progress and can be updated and improved. Fix a small pr ## First — bootstrap the workspace -The workspace is a git-isolated clone of the organization repositories under `~/.msxorg` by default. Set it up before reading context. Use a separate organization-named root, such as `~/.psmodule` for PSModule. Existing context repositories must be clean, on their default branch, and exactly synchronized with the remote: +The workspace is a git-isolated clone of the organization documentation repository under `~/.msxorg` by default. Set it up before reading context. Use a separate organization-named root, such as `~/.psmodule` for PSModule. The existing context repository must be clean, on its default branch, and exactly synchronized with the remote: ```powershell $workspaceRoot = if ($env:MSX_WORKSPACE_ROOT) { $env:MSX_WORKSPACE_ROOT } else { Join-Path $HOME '.msxorg' } $docsUrl = if ($env:MSX_DOCS_URL) { $env:MSX_DOCS_URL } else { 'https://github.com/MSXOrg/docs.git' } -$memoryUrl = if ($env:MSX_MEMORY_URL) { $env:MSX_MEMORY_URL } else { 'https://github.com/MSXOrg/memory.git' } $docs = Join-Path $workspaceRoot 'docs' $docsBacking = "$docs.git" if ((Test-Path $docs) -and -not (Test-Path (Join-Path $docs '.git'))) { @@ -108,14 +107,12 @@ $projects = @( Name = 'MSXOrg' Path = '' DocsUrl = $docsUrl - MemoryUrl = $memoryUrl } # Add project-specific entries when this template is adopted there: # @{ # Name = 'PSModule' # Path = '' # DocsUrl = 'https://github.com/PSModule/docs.git' - # MemoryUrl = 'https://github.com/PSModule/memory.git' # } ) & (Join-Path $docs 'bootstrap/Initialize-MsxWorkspace.ps1') -Root $workspaceRoot -Project $projects @@ -130,11 +127,9 @@ This produces: - `~/.msxorg/docs.git` — bare backing repository for central docs. - `~/.msxorg/docs` — clean, readable main worktree containing ways of working, standards, and workflow guidance. -- `~/.msxorg/memory` — what has been learned before: durable notes and prior session context. 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 @@ -142,7 +137,6 @@ Each clone has repository-local git config only; it never modifies the global gi 2. Start at `~/.msxorg/docs/src/docs/index.md`. 3. Follow the Ways of Working index to `Workflow.md`. 4. Infer the current stage from the task and its artifacts, then read the linked stage procedure. -5. Read the relevant standards, repository context, and `~/.msxorg/memory`. In a repository, its root `AGENTS.md` names the host and organization and lists the order to read in. This file carries the bootstrap and the segmentation step; the repository file carries the route. Neither restates the other. @@ -167,9 +161,7 @@ Read `Ways-of-Working/Session-Interactions.md` in the canonical docs for what ea 2. Read its `.github/CONTRIBUTING.md` for the contribution and review contract. 3. Use a dedicated worktree and the branch naming defined by the canonical Ways of Working. 4. Make small, descriptive micro-commits and push every commit so remote state, CI, and the draft pull request stay current. -5. Capture verified reusable lessons in organization memory, following that repository's own instructions. ## Two write rules - **Docs change through topic worktrees and pull requests.** Create a topic worktree from `~/.msxorg/docs.git`; never branch or work inside the canonical `~/.msxorg/docs` main worktree. -- **Memory follows repository policy.** Read the selected memory repository's `AGENTS.md` and `CONTRIBUTING.md` before writing. diff --git a/bootstrap/Initialize-MsxWorkspace.ps1 b/bootstrap/Initialize-MsxWorkspace.ps1 index 7d1091d..9516bc8 100644 --- a/bootstrap/Initialize-MsxWorkspace.ps1 +++ b/bootstrap/Initialize-MsxWorkspace.ps1 @@ -7,7 +7,7 @@ .DESCRIPTION The single starting point for every agent. It ensures the central - documentation and memory repositories for each configured project exist + documentation repositories for each configured project exist locally under one dedicated workspace, so an agent reads current canonical context regardless of which repository it is working in. @@ -16,7 +16,6 @@ - Each docs repository uses a bare backing repository plus a canonical clean default-branch worktree. Topic branches use separate worktrees. - - Each memory repository remains a simple default-branch checkout. - Every checkout gets repository-local git config only. Nothing here modifies global git config or the working product repository. - The script synchronizes context but never writes or pushes repository content. @@ -40,11 +39,10 @@ Name = 'PSModule' Path = '' DocsUrl = 'https://github.com/PSModule/docs.git' - MemoryUrl = 'https://github.com/PSModule/memory.git' } ) ./Initialize-MsxWorkspace.ps1 -Project $projects - Installs a project's docs and memory under a project-specific workspace path. + Installs a project's docs under a project-specific workspace path. .OUTPUTS [pscustomobject] with Repository, Path, BackingPath, and Changes for each @@ -52,7 +50,7 @@ #> [CmdletBinding(SupportsShouldProcess)] param( - # The organization workspace root under which 'docs' and 'memory' are placed. + # The organization workspace root under which documentation is placed. [Parameter()] [ValidateNotNullOrEmpty()] [string] $Root = (Join-Path $HOME '.msxorg'), @@ -67,7 +65,7 @@ param( [ValidateNotNullOrEmpty()] [string] $UserEmail = 'MariusStorhaug@users.noreply.github.com', - # Projects whose canonical docs and memory repositories must be synchronized. + # Projects whose canonical documentation repositories must be synchronized. [Parameter()] [ValidateNotNullOrEmpty()] [hashtable[]] $Project = @( @@ -75,7 +73,6 @@ param( Name = 'MSXOrg' Path = '' DocsUrl = 'https://github.com/MSXOrg/docs.git' - MemoryUrl = 'https://github.com/MSXOrg/memory.git' } ) ) @@ -280,9 +277,9 @@ function Set-ContextIdentity { $projectNames = [Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase) $repositories = foreach ($projectDefinition in $Project) { - foreach ($key in @('Name', 'Path', 'DocsUrl', 'MemoryUrl')) { + foreach ($key in @('Name', 'Path', 'DocsUrl')) { if (-not $projectDefinition.ContainsKey($key) -or $null -eq $projectDefinition[$key]) { - throw "Project definitions require Name, Path, DocsUrl, and MemoryUrl. Missing '$key'." + throw "Project definitions require Name, Path, and DocsUrl. Missing '$key'." } } @@ -302,7 +299,6 @@ $repositories = foreach ($projectDefinition in $Project) { $projectPath = $pathSegments -join [IO.Path]::DirectorySeparatorChar $docsPath = if ($projectPath) { Join-Path $projectPath 'docs' } else { 'docs' } - $memoryPath = if ($projectPath) { Join-Path $projectPath 'memory' } else { 'memory' } [pscustomobject]@{ Name = "$projectName/docs" Project = $projectName @@ -312,15 +308,6 @@ $repositories = foreach ($projectDefinition in $Project) { Url = [string] $projectDefinition.DocsUrl Changes = 'pull requests' } - [pscustomobject]@{ - Name = "$projectName/memory" - Project = $projectName - ProjectPath = $projectPath - Kind = 'memory' - RelativePath = $memoryPath - Url = [string] $projectDefinition.MemoryUrl - Changes = 'repository policy' - } } $occupiedPaths = foreach ($repository in $repositories) { @@ -367,23 +354,10 @@ for ($left = 0; $left -lt $occupiedPaths.Count; $left++) { } } -foreach ($repository in $repositories | Where-Object Kind -eq 'memory') { - $memoryPath = Join-Path $Root $repository.RelativePath - $memoryGitEntry = Join-Path $memoryPath '.git' - if (Test-Path $memoryGitEntry -PathType Leaf) { - throw "Memory context '$memoryPath' is a worktree, but memory requires a simple checkout with a .git directory." - } - if ((Test-Path $memoryPath) -and -not (Test-Path $memoryGitEntry -PathType Container)) { - throw "Memory context '$memoryPath' is not a supported simple git checkout." - } -} - foreach ($repository in $repositories) { $contextPath = Join-Path $Root $repository.RelativePath $gitEntry = Join-Path $contextPath '.git' - if ($repository.Kind -eq 'memory' -and (Test-Path $gitEntry -PathType Container)) { - Assert-ContextOrigin -GitPath $contextPath -RepositoryUrl $repository.Url - } elseif ($repository.Kind -eq 'docs') { + if ($repository.Kind -eq 'docs') { if (Test-Path $gitEntry -PathType Container) { Assert-ContextOrigin -GitPath $contextPath -RepositoryUrl $repository.Url } elseif (Test-Path $gitEntry -PathType Leaf) { @@ -404,34 +378,6 @@ if ($PSCmdlet.ShouldProcess($Root, 'Create workspace root')) { $results = foreach ($repo in $repositories) { $path = Join-Path $Root $repo.RelativePath - if ($repo.Kind -eq 'memory') { - $memoryGitEntry = Join-Path $path '.git' - if (Test-Path $memoryGitEntry -PathType Leaf) { - throw "Memory context '$path' is a worktree, but memory requires a simple checkout with a .git directory." - } - if (-not (Test-Path $memoryGitEntry -PathType Container)) { - if (Test-Path $path) { - throw "Cannot clone memory into '$path': it exists but is not a supported simple git checkout." - } - if ($PSCmdlet.ShouldProcess($repo.Url, "Clone memory into '$path'")) { - New-Item -ItemType Directory -Path (Split-Path -Parent $path) -Force | Out-Null - git clone --quiet $repo.Url $path - if ($LASTEXITCODE -ne 0) { - throw "git clone failed for $($repo.Url) (exit $LASTEXITCODE). Check access and credentials." - } - } - } - Sync-ContextCheckout -Path $path -RepositoryUrl $repo.Url -Confirm:$false | Out-Null - Set-ContextIdentity -Path $path -Name $UserName -Email $UserEmail -Confirm:$false - [pscustomobject]@{ - Repository = $repo.Name - Path = $path - BackingPath = $null - Changes = $repo.Changes - } - continue - } - $expectedBackingPath = "$path.git" $backingPath = $null $gitEntry = Join-Path $path '.git' diff --git a/bootstrap/README.md b/bootstrap/README.md index 9a0562d..e04b42f 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -1,24 +1,21 @@ # Bootstrap -The single starting point for agents: a git-isolated local clone of the MSXOrg repositories under `~/.msxorg`, plus the instruction that sends every agent there first. +The single starting point for agents: a git-isolated local clone of the MSXOrg documentation repository under `~/.msxorg`, plus the instruction that sends every agent there first. ## Contents -- `Initialize-MsxWorkspace.ps1` — idempotent setup. Clones `MSXOrg/docs` and `MSXOrg/memory` under `~/.msxorg`, requires existing clones to exactly match their remote default branches, 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). +- `Initialize-MsxWorkspace.ps1` — idempotent setup. Clones `MSXOrg/docs` under `~/.msxorg`, requires the existing clone to exactly match its remote default branch, 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. Install it once per machine (below). ## The model - `~/.msxorg/docs` is **read context** — the ways of working, coding standards, and agent workflow. Changes to it go through **pull requests**. - `~/.msxorg/docs.git` is the bare backing repository for the readable, clean `~/.msxorg/docs` main worktree. -- `~/.msxorg/memory` is **durable context** — notes and session history governed by that repository's contribution policy. -- `~/./docs.git` and `docs/` provide the same bare+main-worktree model for optional organization docs; `memory/` remains a simple checkout. +- `~/./docs.git` and `docs/` provide the same bare+main-worktree model for each organization's documentation. -> **Prerequisite:** `MSXOrg/memory` is a private repository — the bootstrap needs access to it (and working github.com credentials) to clone or update memory. +Before the repository is used, bootstrap fetches it and requires a clean checkout on the remote default branch at the exact remote head. A dirty, locally ahead, diverged, wrong-branch, or unreachable context repository stops bootstrap; stale context is never treated as a successful fallback. -Before either repository is used, bootstrap fetches it and requires a clean checkout on the remote default branch at the exact remote head. A dirty, locally ahead, diverged, wrong-branch, or unreachable context repository stops bootstrap; stale context is never treated as a successful fallback. - -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. +Keeping the workspace separate and git-isolated means an agent reads the same documentation 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. The loaded `AGENTS.md` points to the roots; discovery happens in documentation. Start at `~/.msxorg/docs/src/docs/index.md`, follow Ways of Working to Workflow, infer the current stage, and read the linked procedure. Clear task language can shortcut stage selection, but no skill or instruction file owns a separate copy of the process. @@ -29,7 +26,6 @@ Run the bootstrap: ```powershell $workspaceRoot = if ($env:MSX_WORKSPACE_ROOT) { $env:MSX_WORKSPACE_ROOT } else { Join-Path $HOME '.msxorg' } $docsUrl = if ($env:MSX_DOCS_URL) { $env:MSX_DOCS_URL } else { 'https://github.com/MSXOrg/docs.git' } -$memoryUrl = if ($env:MSX_MEMORY_URL) { $env:MSX_MEMORY_URL } else { 'https://github.com/MSXOrg/memory.git' } $docs = Join-Path $workspaceRoot 'docs' $docsBacking = "$docs.git" if ((Test-Path $docs) -and -not (Test-Path (Join-Path $docs '.git'))) { @@ -124,7 +120,6 @@ $projects = @( Name = 'MSXOrg' Path = '' DocsUrl = $docsUrl - MemoryUrl = $memoryUrl } ) & (Join-Path $docs 'bootstrap/Initialize-MsxWorkspace.ps1') -Root $workspaceRoot -Project $projects @@ -135,7 +130,7 @@ if ($LASTEXITCODE -ne 0) { ## Add project context -The default project is MSXOrg. A repository in another project declares additional docs and memory coordinates in its agent installation chapter and passes them to the same bootstrap: +The default project is MSXOrg. A repository in another project declares additional documentation coordinates in its agent installation chapter and passes them to the same bootstrap: ```powershell $projects = @( @@ -143,13 +138,11 @@ $projects = @( Name = 'MSXOrg' Path = '' DocsUrl = 'https://github.com/MSXOrg/docs.git' - MemoryUrl = 'https://github.com/MSXOrg/memory.git' } @{ Name = 'PSModule' Path = '' DocsUrl = 'https://github.com/PSModule/docs.git' - MemoryUrl = 'https://github.com/PSModule/memory.git' } ) & (Join-Path $docs 'bootstrap/Initialize-MsxWorkspace.ps1') -Root (Join-Path $HOME '.psmodule') -Project $projects @@ -175,4 +168,4 @@ Wire it into the tools so it runs as the first instruction: 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. +> **Override this if you are not the maintainer.** With the default, commits 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. diff --git a/src/docs/Capabilities/agentic-development/conformance.md b/src/docs/Capabilities/agentic-development/conformance.md index f0ce149..df6591d 100644 --- a/src/docs/Capabilities/agentic-development/conformance.md +++ b/src/docs/Capabilities/agentic-development/conformance.md @@ -22,9 +22,9 @@ A conformant repository MUST provide all of the following. | **A router agent file** | The repository root holds a single agent instruction file, and it routes rather than instructs ([design](design.md#pointer-files)) | | **Reading order** | The router states the order in which context is read, from repository-local to organization-canonical | | **Client routes** | Every supported runtime's expected instruction path exists and resolves to the router, carrying no content of its own ([client behavior](design.md#client-behavior)) | -| **Canonical coordinates** | The router names the organization's canonical documentation and memory locations, so context is reachable without prior knowledge | +| **Canonical coordinates** | The router names the organization's canonical documentation location, so context is reachable without prior knowledge | | **Freshness** | Canonical context is refreshed at the start of every session, in every runtime ([refresh hooks](design.md#refresh-hooks)) | -| **Precedence** | The router states that local files never override a standard and that memory never overrides documentation | +| **Precedence** | The router states that local files never override a standard | The baseline is small on purpose. Every item is something an agent needs before it can find anything else; nothing on the list is a judgement about how the repository should be diff --git a/src/docs/Capabilities/agentic-development/decisions/document-architecture-and-memory-boundaries.md b/src/docs/Capabilities/agentic-development/decisions/document-architecture-and-memory-boundaries.md deleted file mode 100644 index 0981d59..0000000 --- a/src/docs/Capabilities/agentic-development/decisions/document-architecture-and-memory-boundaries.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: Document architecture and memory boundaries -description: The topic-and-artifact documentation model, minimal OKF-style metadata, and separate durable memory repository. ---- - -# Document architecture and memory boundaries - -## Context - -MSX documentation is navigable cheaply by humans and agents, agent -configuration points to canonical knowledge, and durable lessons have a shared -home. The architecture establishes those boundaries without duplicating -documentation across classifications or repositories. - -## Decision - -MSX uses the [Documentation Model](../../../Ways-of-Working/Documentation-Model.md) -as the documentation architecture: - -- Paths are topic- and scope-oriented, and every area is navigated through - `index.md`. -- The spec, design, guide, reference, decision-record, and research artifact - tiers classify content by the reader's need. -- Pages use the minimal OKF-style model: Markdown, YAML `title` and - `description` front matter, one primary concept per page, and stable paths. -- `MSXOrg/docs` remains the reviewed, pull-request-only canonical knowledge - base. Durable working knowledge belongs in the separate private - `MSXOrg/memory` repository; session notes remain local and ignored. - -MSX does not add Diataxis quadrant directories or `diataxis` metadata. The -artifact tiers already route the same reader needs while keeping related -subject matter together. MSX also does not adopt strict OKF conformance fields -or per-area `log.md` files: the only metadata queried by navigation is title -and description, and Git history is the authoritative changelog. - -## Consequences - -Contributors file a page by subject and artifact tier, then run the index -generator. Readers and agents traverse the same indexes without loading an -unrelated quadrant. Tooling validates the metadata it consumes and validates -links, while review keeps page boundaries and cross-references coherent. - -Agents propose changes to canonical documentation through pull requests. -Agents commit durable, factual lessons to `MSXOrg/memory` under its -[memory-writing rules](../design.md#memory-writing-rules); they never use this -public documentation repository as a low-ceremony dump. - -Changes to these boundaries use a new decision record that supersedes this one. diff --git a/src/docs/Capabilities/agentic-development/decisions/index.md b/src/docs/Capabilities/agentic-development/decisions/index.md index 4d64238..d414191 100644 --- a/src/docs/Capabilities/agentic-development/decisions/index.md +++ b/src/docs/Capabilities/agentic-development/decisions/index.md @@ -8,10 +8,4 @@ description: Immutable records of one-way-door choices in the agentic developmen These records explain choices that constrain the framework. A later decision supersedes an earlier one; it does not rewrite it. - - -| Page | Description | -| --- | --- | -| [Document architecture and memory boundaries](document-architecture-and-memory-boundaries.md) | The topic-and-artifact documentation model, minimal OKF-style metadata, and separate durable memory repository. | - - +There are currently no decisions recorded for this capability. diff --git a/src/docs/Capabilities/agentic-development/design.md b/src/docs/Capabilities/agentic-development/design.md index 2ae31ab..2b0d7cc 100644 --- a/src/docs/Capabilities/agentic-development/design.md +++ b/src/docs/Capabilities/agentic-development/design.md @@ -1,11 +1,11 @@ --- title: Design -description: How the agentic development framework is built — OKF documentation, org memory, thin repo pointers, and deterministic context resolution. +description: How the agentic development framework is built — OKF documentation, thin repo pointers, and deterministic context resolution. --- # Agentic Development — Design -The behavior in the [spec](spec.md) is delivered by an organization-level documentation and memory pair, adopted by each product repository through thin pointer files. The design keeps project knowledge in one reviewed place, keeps working memory in one durable place, and lets each agent runtime adapt without copying process knowledge. +The behavior in the [spec](spec.md) is delivered by an organization-level documentation repository, adopted by each product repository through thin pointer files. The design keeps project knowledge in one reviewed place and lets each agent runtime adapt without copying process knowledge. ## Organization anatomy @@ -14,18 +14,17 @@ The GitHub organization is the project boundary. The host distinguishes work fro ```text // docs/ # canonical knowledge base; changes through pull requests - memory/ # durable agent and team memory; versioned working knowledge / # product or component repository / ``` Current project scopes follow the same shape: -| Host | Organization | Docs | Memory | -| --- | --- | --- | --- | -| `github.com` | `MSXOrg` | `MSXOrg/docs` | `MSXOrg/memory` | -| `github.com` | `PSModule` | `PSModule/docs` | `PSModule/memory` | -| `` | `` | `/docs` | `/memory` | +| Host | Organization | Docs | +| --- | --- | --- | +| `github.com` | `MSXOrg` | `MSXOrg/docs` | +| `github.com` | `PSModule` | `PSModule/docs` | +| `` | `` | `/docs` | The last row is the general case: any adopting organization on any GitHub host — public or an enterprise instance — plugs into the same shape without changing the framework. @@ -43,18 +42,6 @@ The `docs` repository is the canonical knowledge base. It owns: Changes to `docs` happen through pull requests because this repository defines durable project intent. -### `memory` - -The `memory` repository is the durable working-memory store. It owns: - -- recurring gotchas and lessons learned; -- active project context that should survive a single chat session; -- workflow-stage working knowledge; -- issue, PR, and incident notes worth reusing; -- project-specific preferences that are factual rather than private user preference. - -Memory pages stay short and factual. They are safe to read before work begins and safe to improve when a lesson is learned. - ### Product repositories Product repositories carry local context and thin pointers: @@ -73,11 +60,11 @@ Product repositories carry local context and thin pointers: docs/ # architecture and domain context ``` -The repository owns only repository-specific nuance, and each kind has a file that owns it: `README.md` for what the repository is and how it builds, `.github/CONTRIBUTING.md` for contribution mechanics, `docs/` for architecture and domain context, and path-scoped rule files for local caveats. `AGENTS.md` points at them and holds none of it. Cross-cutting standards remain in `docs`; reusable lessons remain in `memory`. Thin means "no duplicated reusable process," not "discard the local operating contract" — the contract lives, it just lives in the file a human would read. +The repository owns only repository-specific nuance, and each kind has a file that owns it: `README.md` for what the repository is and how it builds, `.github/CONTRIBUTING.md` for contribution mechanics, `docs/` for architecture and domain context, and path-scoped rule files for local caveats. `AGENTS.md` points at them and holds none of it. Cross-cutting standards remain in `docs`. Thin means "no duplicated reusable process," not "discard the local operating contract" — the contract lives, it just lives in the file a human would read. ## OKF page model -Both `docs` and `memory` use the [Open Knowledge Format](../../Dictionary/index.md#open-knowledge-format) style: Markdown with YAML frontmatter, one concept per page, paths as stable identity, and indexes as navigation maps. +The `docs` repository uses the [Open Knowledge Format](../../Dictionary/index.md#open-knowledge-format) style: Markdown with YAML frontmatter, one concept per page, paths as stable identity, and indexes as navigation maps. Minimum page frontmatter: @@ -88,20 +75,6 @@ description: One-line description of the page. --- ``` -Memory pages MAY add scope-oriented metadata when it helps agents filter context: - -```yaml ---- -title: GitHub Actions cache gotchas -description: Reusable notes for cache failures and permissions. -scope: project -tags: - - github-actions - - cache - - gotcha ---- -``` - The body stays concise. If a page grows into multiple concepts, split it and link through the nearest `index.md`. ## Indexes as the mindmap @@ -118,14 +91,9 @@ docs/ Capabilities/index.md Capabilities/agentic-development/index.md -memory/ - index.md - agents/index.md - knowledge/index.md - gotchas/index.md ``` -Every index describes what sits below it. Generated indexes are preferred where tooling exists; manually maintained indexes are acceptable when the memory repository is intentionally lightweight. +Every index describes what sits below it. Generated indexes are preferred where tooling exists. ## Context resolution flow @@ -134,14 +102,14 @@ flowchart TD start["Agent receives task"] --> policy["System and client policy"] policy --> user["User-global preferences"] user --> pointer["Read AGENTS.md pointer"] - pointer --> locate["Resolve host, org, docs, and memory roots"] + pointer --> locate["Resolve host, org, and docs root"] locate --> host{"Which project scope?"} host -->|"github.com/MSXOrg"| msx["MSXOrg context"] host -->|"github.com/PSModule"| psmodule["PSModule context"] host -->|"any adopting org"| other["<host>/<org> context"] - msx --> refresh["Refresh selected docs + memory
stop unless exactly synchronized"] + msx --> refresh["Refresh selected docs
stop unless exactly synchronized"] psmodule --> refresh other --> refresh refresh --> repo["Read README, CONTRIBUTING,
and local docs"] @@ -151,8 +119,7 @@ flowchart TD docs --> workflow["Follow indexes to Workflow"] workflow --> stage["Infer current stage
read canonical procedure"] - stage --> memory["Read memory last"] - memory --> task["Read issue, PR, branch, diff, diagnostics, and open files"] + stage --> task["Read issue, PR, branch, diff, diagnostics, and open files"] task --> act["Act and follow stage handoffs"] act --> newpath{"New file path touched?"} @@ -175,17 +142,14 @@ This repository is `github.com/MSXOrg/`. Read in this order: 2. `.github/CONTRIBUTING.md` — how a change is made and reviewed here. 3. `docs/index.md` — this repository's own documentation. 4. `~/.msxorg/docs/src/docs/index.md` — the organization standards. -5. `~/.msxorg/memory/index.md` — durable lessons, read last. - -Read nearest first. A local file never overrides a standard, and memory never -overrides documentation. +Read nearest first. A local file never overrides a standard. ``` A router lists the destinations that exist in that repository, written as the paths that repository actually uses — the ones above are an example, not a required layout. A repository with no documentation of its own drops that line; one that publishes the standards resolves steps 3 and 4 to the same tree and drops the duplicate. Writing a real path matters more than matching the example, because the router is read literally. The index trail is the default. A clear prompt can shortcut stage discovery: `Review this PR ` enters Review, `Make this issue ` enters Define, and `Implement ` enters Implement. These phrases are routing hints interpreted by [Workflow](../../Ways-of-Working/Workflow.md#find-the-current-stage), not commands with independent procedures. -> **Reading order vs. conflict precedence** — the router reads the repository's own files first and widens outward, because nearest context is cheapest and most specific. Precedence runs the other way: repository files add nuance and narrow exceptions and never silently override an organization standard unless that standard permits a local exception, and memory never overrides documentation. +> **Reading order vs. conflict precedence** — the router reads the repository's own files first and widens outward, because nearest context is cheapest and most specific. Precedence runs the other way: repository files add nuance and narrow exceptions and never silently override an organization standard unless that standard permits a local exception. `.claude/CLAUDE.md` is a single import: @@ -213,11 +177,9 @@ A local bootstrap makes central context predictable: ~/.msxorg/ docs.git/ # MSXOrg/docs bare backing repository docs/ # clean MSXOrg/docs main worktree - memory/ # simple MSXOrg/memory checkout ~/.psmodule/ docs.git/ # PSModule/docs bare backing repository docs/ # PSModule/docs main worktree - memory/ # PSModule/memory checkout ``` The bootstrap clones missing repositories and fetches every existing context repository before use. Each clone must be clean, checked out on the remote default branch, and exactly equal to the fetched remote head. A dirty, locally ahead, diverged, wrong-branch, or unreachable clone stops context resolution; the agent does not use a possibly stale local copy. Bootstrap writes repository-local git configuration only. @@ -261,31 +223,13 @@ precisely to replace that judgement with a check. Each shape's obligations beyond the refresh — its entry file, tool declaration, and identity — are set out in [Runtime Integration](runtime-integration.md). -## Memory writing rules - -Agents write memory only when a lesson is likely to matter again. Good memory is: - -- short and factual; -- scoped to the organization; -- linked to the issue, PR, repository, or document that proves it; -- free of secrets, credentials, and private personal notes; -- updated or removed when it becomes wrong. - -Memory is written by **horizon**: organization-wide lessons and per-repository facts are -durable and shared, while notes about the task in hand are session-scoped and never pushed -([memory repository template](memory-template.md#memory-has-three-horizons)). A session note -becomes durable only by being deliberately promoted and rewritten as a statement of fact. - -Durable memory is committed and pushed as it is written, one commit per discrete lesson, so -that nothing depends on a session ending cleanly. - ## Client behavior Different clients load different files, but the framework keeps the same dependency direction. A client that reads `AGENTS.md` needs no file of its own; a client that does not gets a route to it. | Client | Reads | Behavior | | --- | --- | --- | -| Cross-client agents | `AGENTS.md` | Read the router, then follow its order outward from the repository to the organization documentation and memory. | +| Cross-client agents | `AGENTS.md` | Read the router, then follow its order outward from the repository to the organization documentation. | | Claude Code | `.claude/CLAUDE.md` | Imports the router with `@../AGENTS.md` and adds nothing else. | | Copilot Chat in VS Code, and the Copilot cloud agent | `AGENTS.md` | Read `AGENTS.md` natively and follow its route list. Path-scoped `.github/instructions/*.instructions.md` files still apply when their `applyTo` pattern matches a file being read, generated, reviewed, or edited. | | Copilot surfaces without `AGENTS.md` support | `.github/copilot-instructions.md` | Copilot Chat on GitHub.com, Visual Studio, JetBrains, Eclipse, and Copilot code review outside GitHub.com read this file. It routes them to the router and adds nothing else. | @@ -298,10 +242,9 @@ Because Copilot code review reads the head branch, a pull request that changes ` | Failure | Design response | | --- | --- | | Repository does not identify its organization context | Infer from remote URL; ask when ambiguous. | -| A docs or memory clone is missing or cannot synchronize | Bootstrap or repair it, then retry. Stop context resolution until every canonical context repository passes the freshness gate. | +| A docs clone is missing or cannot synchronize | Bootstrap or repair it, then retry. Stop context resolution until the canonical context repository passes the freshness gate. | | Pointer file duplicates central standards | Replace duplicated content with a route during review. A client file holds a pointer, not a copy. | | A skill, command, named agent, or instruction file defines a workflow stage | Delete the duplicate procedure and link to Workflow or its stage page. | -| Memory conflicts with docs | Docs win; memory is corrected or removed. | | Two organizations are open in one workspace | Select by active repository; ask before cross-project changes. | | A client ignores one pointer format | Add a route file under the filename that client reads, containing only a pointer to `AGENTS.md`. | | A repository file contradicts an organization standard | The standard governs. Narrow the local file to the exception the standard permits, or change the standard. | @@ -309,18 +252,14 @@ Because Copilot code review reads the head branch, a pull request that changes ` ## Adoption path 1. Create or identify the organization `docs` repository. -2. Create or identify the organization `memory` repository, using the [Memory Repository Template](memory-template.md) as the starting scaffold. -3. Add `docs/index.md` and `memory/index.md` as the two root maps. -4. Add the canonical Workflow and linked stage procedures to `docs`. -5. Add starter memory sections to `memory`. -6. Add the `AGENTS.md` router to each product repository, plus a route for every client that cannot read it. -7. Add a bootstrap that keeps local docs and memory clones present and exactly synchronized before use. -8. Review new work for pointer discipline: facts live once, links point to them. +2. Add the canonical Workflow and linked stage procedures to `docs`. +3. Add the `AGENTS.md` router to each product repository, plus a route for every client that cannot read it. +4. Add a bootstrap that keeps the local docs clone present and exactly synchronized before use. +5. Review new work for pointer discipline: facts live once, links point to them. ## Where this connects - [Spec](spec.md) — the requirements this design delivers. -- [Memory Repository Template](memory-template.md) — the concrete scaffold every organization's canonical `memory` repository instantiates. - [MCP Servers](mcp-servers.md) — the shared tool layer every runtime declares in its own format. - [Plugin Distribution](plugin-distribution.md) — how named intents are packaged and kept pointer-based. - [Runtime Integration](runtime-integration.md) — what each runtime shape supplies, and why it never supplies process. diff --git a/src/docs/Capabilities/agentic-development/index.md b/src/docs/Capabilities/agentic-development/index.md index e2c1bb9..ef8689f 100644 --- a/src/docs/Capabilities/agentic-development/index.md +++ b/src/docs/Capabilities/agentic-development/index.md @@ -1,21 +1,20 @@ --- title: Agentic Development -description: The framework for org-scoped docs and memory repositories that give agents project-specific standards, working knowledge, and behavior. +description: The framework for org-scoped documentation that gives agents project-specific standards and behavior. --- # Agentic Development -The Agentic Development framework makes an organization the operating boundary for human and agent work. Each organization owns a `docs` repository for canonical knowledge and a `memory` repository for accumulated working context; every product repository carries a short router that points to those roots, and keeps its own nuance in the files a human already reads. +The Agentic Development framework makes an organization the operating boundary for human and agent work. Each organization owns a `docs` repository for canonical knowledge; every product repository carries a short router that points to that root, and keeps its own nuance in the files a human already reads. -A repository adopts the framework by carrying a short router and the client routes that reach it, and by letting agents read outward — the repository's own files first, then the organization documentation and memory, then the current task. The organization selects *which* context applies; the reading order decides what is read first. +A repository adopts the framework by carrying a short router and the client routes that reach it, and by letting agents read outward — the repository's own files first, then the organization documentation, then the current task. The organization selects *which* context applies; the reading order decides what is read first. | Page | Description | | --- | --- | -| [Spec](spec.md) | Requirements for refresh-first, index-first agentic development through canonical documentation, memory, and thin pointers. | -| [Design](design.md) | How the agentic development framework is built — OKF documentation, org memory, thin repo pointers, and deterministic context resolution. | -| [Memory Repository Template](memory-template.md) | The concrete, copy-pasteable scaffold every organization's memory repository instantiates, and why it deliberately breaks from the Repository Standard. | +| [Spec](spec.md) | Requirements for refresh-first, index-first agentic development through canonical documentation and thin pointers. | +| [Design](design.md) | How the agentic development framework is built — OKF documentation, thin repo pointers, and deterministic context resolution. | | [MCP Servers](mcp-servers.md) | How one logical set of tool servers is defined once and declared by every runtime in its own format, so a documented procedure does not depend on which client runs it. | | [Runtime Integration](runtime-integration.md) | How a runtime is wired into the framework — the entry file it reads, the lifecycle point its refresh attaches to, the permissions it needs, and what a new runtime must supply to be supported. | | [Plugin Distribution](plugin-distribution.md) | How recurring workflows are packaged as named intents that point to canonical documentation, and why a packaged shortcut never carries a copy of the procedure. | diff --git a/src/docs/Capabilities/agentic-development/memory-template.md b/src/docs/Capabilities/agentic-development/memory-template.md deleted file mode 100644 index e96a733..0000000 --- a/src/docs/Capabilities/agentic-development/memory-template.md +++ /dev/null @@ -1,178 +0,0 @@ ---- -title: Memory Repository Template -description: The concrete, copy-pasteable scaffold every organization's memory repository instantiates, and why it deliberately breaks from the Repository Standard. ---- - -# Memory Repository Template - -[Spec](spec.md) and [Design](design.md) require every adopting organization to have a -`memory` repository, and the design's [organization anatomy](design.md#organization-anatomy) -already names `MSXOrg/memory` and `PSModule/memory` as canonical examples. Neither design -document defines an exact file layout — this page is that layout. It is the one scaffold -every adopting organization's `memory` repository instantiates. Content differs per -organization; structure does not. - -## Memory has three horizons - -Not every remembered thing has the same lifetime, and treating them alike is what makes a -memory repository degrade. A convention that holds everywhere, a fact true of one -repository, and a note that matters only until the current task finishes are three -different kinds of knowledge, and mixing them means the durable content is buried in the -ephemeral. - -The scaffold therefore separates memory by **horizon** — how long the entry stays true and -how widely it applies: - -| Horizon | Scope | Lifetime | Shared | -| --- | --- | --- | --- | -| **User** | Applies across every repository in the organization | Until the practice itself changes | Yes — committed and pushed | -| **Repository** | Applies to one repository | As long as that repository keeps the shape the entry describes | Yes — committed and pushed | -| **Session** | Applies to work in progress right now | Until the task finishes | No — local only, never pushed | - -Horizon is a property of the entry, not of its subject. A workaround for one repository's -build quirk is repository-scoped even though it is about a build; a decision to always -verify a command before recording it is user-scoped even though it was learned in one -repository. - -## Scaffold - -```text -memory/ -├── README.md # front door: what this repo is, that it's private, "commit straight to main, no PR" -├── CONTRIBUTING.md # short: direct push to main, no PR/review gate, keep entries short and factual -├── AGENTS.md # cross-client agent entry point: orients an agent landing here cold, points at index.md and the memory-writing rules -├── .gitattributes -├── .gitignore # ignores session/ so ephemeral notes are never pushed -├── index.md # OKF root index (okf_version frontmatter), links to the scopes below -├── user/ # organization-wide, durable: conventions, verified commands, recurring gotchas, ecosystem facts -│ └── index.md -├── repo/ # per-repository, durable: one folder per repository worth remembering facts about -│ └── index.md # created lazily: repo//index.md once a repository accumulates facts -└── session/ # ephemeral working notes for the task in hand — git-ignored, never pushed - └── .gitkeep -``` - -`repo//` folders are created lazily, only once a repository accumulates facts worth -remembering — `repo/` starts with nothing but its index in a freshly scaffolded repository. - -## Why `session/` is git-ignored - -A session note is a scratchpad: what has been tried, what the current hypothesis is, which -file is half-edited. It is genuinely useful while the task runs and actively harmful -afterwards, because a later agent reading it cannot tell a live hypothesis from a settled -fact. - -So `session/` is ignored rather than merely short-lived. Ignoring it, instead of relying on -discipline to delete it, means the ephemeral content cannot leak into shared memory at all: - -- An agent MAY write freely to `session/` without weighing whether the note is worth - keeping, which is the only way a scratchpad is useful. -- Nothing in `session/` reaches another person or another machine, so no one inherits - someone else's half-finished reasoning as though it were knowledge. -- Promoting a session note to durable memory is a **deliberate move** into `user/` or - `repo//`, rewritten as a statement of fact. Promotion is the moment the entry gets - reviewed for whether it is actually true, and an ignored folder is what forces that moment - to exist. - -An agent that wants a note to survive the session MUST move it, not leave it and hope. - -## How the scopes map to what memory owns - -[Design](design.md#memory) already states what the `memory` repository owns. Each scope is -one horizon of those responsibilities: - -| Scope | Owns (from [Design](design.md#memory)) | -| --- | --- | -| `user/` | Recurring gotchas and lessons learned, durable facts about the ecosystem and its tools, and project-specific preferences that are factual rather than private user preference. | -| `repo//` | Facts true of one repository: its shape, its quirks, its cross-repository relationships, and issue, pull request, or incident notes worth reusing. | -| `session/` | Active context for the task in hand, which should survive a single chat session but MUST NOT outlive the task. | - -`index.md` is the root map described in [Design's indexes section](design.md#indexes-as-the-mindmap): -it links to `user/index.md` and `repo/index.md` so a human or agent can start at the root and -drill inward. It does not link into `session/`, which has no shared content to index. - -`AGENTS.md` doesn't map to a `memory` ownership bullet — it isn't content memory owns, it's the -framework's [client behavior table](design.md#client-behavior) entry point: "Cross-client agents | -`AGENTS.md` | Read the shared project pointer and local nuance." Every repository in the -framework carries one so an agent landing cold knows where to start; a `memory` repository is no -exception. Its job is narrower than `README.md`'s and different from `CONTRIBUTING.md`'s — it -orients an *agent* specifically, pointing straight at `index.md` and the -[memory writing rules](design.md#memory-writing-rules), while `CONTRIBUTING.md` stays -contribution-process-flavored (direct push, no PR) even though this repository's real audience is -agents, not human contributors. - -## Commit after every discrete action - -Durable memory MUST be committed and pushed as soon as it is written, one commit per -discrete thing learned. - -Batching memory writes until the end of a session is how memory gets lost. An agent session -can end at any point — the task completes, the context window fills, the process is -interrupted — and anything still uncommitted at that moment is gone. A lesson learned in -the first minute and pushed in the first minute survives all three endings. - -Micro-commits also make memory legible in the way documentation is: one commit is one -lesson, so the history reads as a list of things learned rather than a periodic dump. A -memory entry whose commit bundles nine unrelated observations cannot be reverted, cited, or -blamed independently. - -Because memory changes land directly on the default branch -([spec](spec.md#requirements)), there is no batching pressure from a review gate. The only -reason to hold a memory write is that it is not yet true, and an entry that is not yet true -belongs in `session/`. - -## A deliberate exception to the Repository Standard - -[Repository Standard](../../Ways-of-Working/Repository-Standard.md) lists the files every -repository must carry: `LICENSE`, `SECURITY.md`, `SUPPORT.md`, `CODE_OF_CONDUCT.md`, -`.github/dependabot.yml`, `.github/CODEOWNERS`, `.github/pull_request_template.md`, and -more. A `memory` repository intentionally omits all of these. -[Organization Standard](../../Ways-of-Working/Organization-Standard.md) allows an -initiative to define type-specific exceptions to the default file set — this is that -exception, made explicit rather than left as an oversight: - -- **Private, not public.** There is no external audience to license, and no public - vulnerability surface to run a `SECURITY.md` disclosure process against. -- **No PR workflow.** [Spec](spec.md#requirements) allows memory changes to be - lighter-weight than `docs` changes, as long as they stay versioned in git. A - `pull_request_template.md` and `CODEOWNERS` review routing make no sense for a repo - where every change lands as a direct commit to `main`. - See [Memory writing rules](design.md#memory-writing-rules) for what a good direct - commit looks like. This only works in practice once the organization's ruleset stops - requiring pull requests for `memory` repositories — see - [Repository Type Property](../../Ways-of-Working/Repository-Type-Property.md) for how - that exclusion is implemented via a `Type: Memory` custom property value. -- **No external dependencies.** Plain Markdown files have no supply chain, so - `.github/dependabot.yml` has nothing to update. -- **Small, defined audience.** `SUPPORT.md` and `CODE_OF_CONDUCT.md` exist to set - expectations for a broad or public contributor community; a `memory` repository's - audience is the organization's own humans and agents. - -A `memory` repository still carries `README.md`, `CONTRIBUTING.md`, `AGENTS.md`, `.gitattributes`, -and `.gitignore` — the minimum needed to explain itself and behave predictably in git. The -`.gitignore` is load-bearing rather than conventional here: it is what keeps `session/` out -of the shared history. - -## Visibility - -`memory` repositories default to **private**. Working memory can capture internal -context, half-finished reasoning, and organization-specific detail that isn't meant for a -public audience, even when the adjoining `docs` repository is public. - -Privacy and the `session/` ignore rule solve different problems and neither substitutes for -the other. Privacy decides *who* may read durable memory; the ignore rule decides *what* -becomes durable at all. A private repository full of stale hypotheses is still a repository -an agent will read and believe. - -## Where this connects - -- [Spec](spec.md) — the requirement that every organization has a `memory` repository. -- [Design](design.md) — the organization anatomy, `memory` repository role, and OKF page - model this scaffold implements. -- [Repository Standard](../../Ways-of-Working/Repository-Standard.md) — the default file - set this page's scaffold deliberately departs from. -- [Organization Standard](../../Ways-of-Working/Organization-Standard.md) — how - initiative-defined, type-specific exceptions to the default file set are allowed. -- [Repository Type Property](../../Ways-of-Working/Repository-Type-Property.md) — how a - `Type: Memory` custom property value excludes memory repositories from the org-wide - pull-request-required ruleset so the direct-commit workflow above actually works. diff --git a/src/docs/Capabilities/agentic-development/spec.md b/src/docs/Capabilities/agentic-development/spec.md index 87bb2e5..a55f413 100644 --- a/src/docs/Capabilities/agentic-development/spec.md +++ b/src/docs/Capabilities/agentic-development/spec.md @@ -1,6 +1,6 @@ --- title: Spec -description: Requirements for refresh-first, index-first agentic development through canonical documentation, memory, and thin pointers. +description: Requirements for refresh-first, index-first agentic development through canonical documentation and thin pointers. --- # Agentic Development — Spec @@ -9,29 +9,27 @@ description: Requirements for refresh-first, index-first agentic development thr An agent does useful work only when it knows which project it is serving, which standards apply, and what the team has already learned. That context MUST be project-scoped, durable, reviewable, and readable by humans and agents alike. The project boundary is the GitHub organization — `github.com/MSXOrg`, `github.com/PSModule`, and any other organization that adopts the framework, on any GitHub host. -Each organization owns two canonical repositories: +Each organization owns a canonical repository: - `docs` — the reviewed knowledge base: vision, standards, workflows, specs, designs, glossary, onboarding, and project-wide rules. -- `memory` — the durable agent working memory: lessons learned, recurring gotchas, active context, workflow-stage knowledge, and project-specific operating notes. - -Product repositories do not copy that knowledge. They carry thin pointer files that identify the organization context and direct agents to the relevant `docs` and `memory` roots before acting. +Product repositories do not copy that knowledge. They carry thin pointer files that identify the organization context and direct agents to the relevant `docs` root before acting. ### Principles This framework rests on the [Principles](../../Ways-of-Working/Principles/index.md): - **[Documentation lives close to the thing it documents](../../Ways-of-Working/Principles/Engineering-Practices.md#documentation-lives-close-to-the-thing-it-documents).** Organization-wide ways of working live in the organization `docs` repository; repository-specific nuance lives in the repository. -- **[Everything as Code](../../Ways-of-Working/Principles/Engineering-Practices.md#everything-as-code).** Standards and memory are plain files in git. Changes are reviewed, diffed, and reverted like code. -- **[Written once, referenced everywhere](../../Ways-of-Working/Principles/Software-Design.md#dry-with-judgment).** Agent instructions point to canonical docs and memory rather than duplicating them. +- **[Everything as Code](../../Ways-of-Working/Principles/Engineering-Practices.md#everything-as-code).** Standards are plain files in git. Changes are reviewed, diffed, and reverted like code. +- **[Written once, referenced everywhere](../../Ways-of-Working/Principles/Software-Design.md#dry-with-judgment).** Agent instructions point to canonical docs rather than duplicating them. - **[AI-first development](../../Ways-of-Working/Principles/AI-First-Development.md).** Humans create durable context; agents consume that context and leave useful improvements behind. ## Scope -Applies to any organization that wants a shared project knowledge base and memory store for agents across multiple repositories. +Applies to any organization that wants a shared project knowledge base for agents across multiple repositories. **In scope** -- Organization-level `docs` and `memory` repositories. +- Organization-level `docs` repository. - Markdown documents with YAML frontmatter, following the [Open Knowledge Format](../../Dictionary/index.md#open-knowledge-format) model. - Thin repository pointer files: a required `AGENTS.md` router, and a route to it for every client that cannot read it. - Path-scoped rule files, reserved for local caveats that cannot live in repository or central documentation. @@ -42,7 +40,6 @@ Applies to any organization that wants a shared project knowledge base and memor - Refresh-first, index-first discovery from canonical context repositories to the Workflow and its stage procedures. - Deterministic context resolution by host, organization, repository, path, and task. - Human-reviewed changes to canonical knowledge through pull requests. -- Durable agent memory that can be shared by every person and agent working in the organization. **Out of scope** @@ -55,46 +52,40 @@ Applies to any organization that wants a shared project knowledge base and memor - **Organization is the project boundary.** The framework MUST resolve project context from the Git host and organization before resolving repository-specific context. - **Canonical docs repository.** Each adopting organization MUST have a `docs` repository that owns the reviewed knowledge base. -- **Canonical memory repository.** Each adopting organization MUST have a `memory` repository that owns durable project memory and agent working knowledge. -- **Pluggable project context.** The bootstrap MUST accept project-specific docs and memory coordinates and collision-free relative workspace paths without requiring a fork of its synchronization logic. -- **OKF-style documents.** Knowledge and memory documents MUST be Markdown files with YAML frontmatter, one primary concept per page, and stable paths that act as identity. -- **Small pages and indexes.** Documentation and memory SHOULD prefer small pages, each folder SHOULD have an `index.md`, and indexes MUST let a human or agent navigate inward from the root. -- **Thin pointer files.** Product repositories MUST carry an `AGENTS.md` at the repository root that routes an agent from the repository's own files outward to the organization documentation, any inherited ecosystem documentation, and memory. It MUST be limited to that route list and the repository's own coordinates. It MUST NOT duplicate standards, workflow stages, or reusable process knowledge, and MUST NOT carry build commands, contribution mechanics, or workspace bootstrap steps, each of which has an owning file of its own. +- **Pluggable project context.** The bootstrap MUST accept project-specific documentation coordinates and collision-free relative workspace paths without requiring a fork of its synchronization logic. +- **OKF-style documents.** Knowledge documents MUST be Markdown files with YAML frontmatter, one primary concept per page, and stable paths that act as identity. +- **Small pages and indexes.** Documentation SHOULD prefer small pages, each folder SHOULD have an `index.md`, and indexes MUST let a human or agent navigate inward from the root. +- **Thin pointer files.** Product repositories MUST carry an `AGENTS.md` at the repository root that routes an agent from the repository's own files outward to the organization documentation and any inherited ecosystem documentation. It MUST be limited to that route list and the repository's own coordinates. It MUST NOT duplicate standards, workflow stages, or reusable process knowledge, and MUST NOT carry build commands, contribution mechanics, or workspace bootstrap steps, each of which has an owning file of its own. - **Refresh-first, index-first workflow discovery.** After every canonical context repository passes the freshness gate, a human or agent MUST be able to follow the docs root index to Ways of Working, the canonical Workflow, and the procedure for the current stage. - **Stage resolution from work.** Agents MUST infer the current stage from the prompt and current artifacts. Explicit task language MAY shortcut to the matching stage, but the shortcut MUST resolve to the canonical documentation. - **One process source.** Skills, commands, named agents, and tool-specific instruction files MUST NOT redefine Workflow stages. A client convenience MAY link to a stage procedure and add only runtime mechanics. -- **Segmentation before loading.** An agent MUST segment work by host, organization, repository, path, and task before loading project standards or memory. The repository router MUST supply the coordinates that make this possible by naming its host and organization. The instruction to segment belongs to the user-global bootstrap, which runs before any repository file is read; a per-repository file MUST NOT restate it. +- **Segmentation before loading.** An agent MUST segment work by host, organization, repository, path, and task before loading project standards. The repository router MUST supply the coordinates that make this possible by naming its host and organization. The instruction to segment belongs to the user-global bootstrap, which runs before any repository file is read; a per-repository file MUST NOT restate it. - **Client routes.** A runtime that cannot read `AGENTS.md` under its own filename MUST be given a route file — `.claude/CLAUDE.md`, `.github/copilot-instructions.md`, or the equivalent path for that runtime. A route file MUST contain only a pointer to `AGENTS.md` plus, at most, genuinely runtime-specific configuration that cannot be expressed as documentation. It MUST NOT restate standards, describe workflow behavior, or repeat the reading order. Duplication is a property of content rather than of filenames: a route holds nothing that can drift, so the number of route files is unconstrained while their contents are strictly limited. [Client behavior](design.md#client-behavior) names the exact set an MSX repository carries; an adopting organization MAY carry a different set for the runtimes it uses. -- **Reading order and authority order are distinct.** An agent MUST read nearest context first, in the order the repository router defines. Precedence on conflict MUST run the opposite way: repository-local files MAY add nuance and narrow exceptions but MUST NOT override an organization or inherited ecosystem standard unless that standard permits a local exception, and memory MUST NOT override documentation. -- **Deterministic context resolution.** Agents MUST resolve context in layers: system and client policy, user preferences, the repository router, the context-repository freshness gate, repository context, path-scoped repository rules, organization docs, any inherited ecosystem docs, organization memory, then current task context. -- **Local-first availability.** The docs and memory repositories SHOULD be available locally in a predictable workspace so agents can read them without relying on search or web access. +- **Reading order and authority order are distinct.** An agent MUST read nearest context first, in the order the repository router defines. Precedence on conflict MUST run the opposite way: repository-local files MAY add nuance and narrow exceptions but MUST NOT override an organization or inherited ecosystem standard unless that standard permits a local exception. +- **Deterministic context resolution.** Agents MUST resolve context in layers: system and client policy, user preferences, the repository router, the context-repository freshness gate, repository context, path-scoped repository rules, organization docs, any inherited ecosystem docs, then current task context. +- **Local-first availability.** The docs repository SHOULD be available locally in a predictable workspace so agents can read it without relying on search or web access. - **Fresh context before use.** Every canonical context repository MUST be fetched and exactly synchronized with its remote default branch before its contents are read. Dirty, locally ahead, diverged, wrong-branch, or unreachable repositories MUST stop context resolution rather than fall back to stale content. -- **Working checkouts are not context sources.** Canonical context MUST be read from the context repository clones that passed the freshness gate. A working checkout of a `docs` or `memory` repository — one cloned in order to change it rather than to be governed by it — MUST NOT be used as a context source, whatever path it occupies, because it sits outside the gate: nothing fetches it, and a superseded page in it is readable rather than missing, so the failure is silent. A reader MAY establish whether any checkout is current with `git rev-list --left-right --count HEAD...origin/` after fetching, which reports commits ahead and behind without changing the working tree. +- **Working checkouts are not context sources.** Canonical context MUST be read from the documentation repository clone that passed the freshness gate. A working checkout of the `docs` repository — one cloned in order to change it rather than to be governed by it — MUST NOT be used as a context source, whatever path it occupies, because it sits outside the gate. - **Refresh once per session, not once per machine.** The freshness gate MUST run at the start of every agent session, in every runtime. A workspace that was synchronized at some earlier point MUST NOT be treated as current, because elapsed time is not a state the agent can observe. The refresh MUST be idempotent, so that running it when nothing has changed is cheap and silent; a refresh that is expensive or noisy at steady state gets bypassed, and a bypassed gate is worse than none because the workspace still appears synchronized. -- **Memory is scoped by horizon.** Memory MUST separate entries that apply organization-wide, entries that apply to one repository, and notes that apply only to the task in hand. Session-scoped notes MUST NOT be shared: they MUST be excluded from the repository's history so that a scratchpad cannot be inherited as knowledge. Making a session note durable MUST be a deliberate act of promotion, which is where the entry is checked for whether it is actually true. -- **Durable memory is committed as it is written.** A memory entry MUST be committed and pushed when it is written, one commit per discrete lesson, so that no remembered thing depends on a session ending cleanly. - **One tool layer, declared per runtime.** Where agents use external tools, the set of tool servers MUST be defined once as a logical layer and each runtime MUST declare that same set in its own native configuration format. A runtime MUST NOT define tools of its own that other runtimes lack, because a capability available in one client and absent in another makes the documented procedure conditional on which client is running it. - **Named intents stay pointer-based.** A packaged shortcut for a recurring workflow — however a runtime names it — MUST resolve to the canonical documentation for that workflow and MUST contain only the runtime mechanics needed to get there. It MUST NOT restate the procedure, since a shortcut that carries a copy of the process becomes a second, silently diverging definition of it. - **Advice and authority are separate.** An automated agent MAY analyse work and publish its conclusion as advice on the artifact under review. It MUST NOT be the thing that decides: it MUST NOT overwrite a human's decision, MUST NOT re-apply a decision a human has changed, and MUST NOT commit to the branch it is advising on. Its output is an input to the review, not a substitute for it. - **Coordination happens on durable artifacts.** Where agents and humans coordinate, they MUST do so through the platform's own artifacts — issues, labels, and pull requests — rather than through a channel that leaves no trace in the repository. Intent MUST be separable from implementation: the issue states *what* is wanted and *why*, and the pull request proposes *how*, so that a rejected implementation does not discard the intent. -- **Reviewed knowledge changes.** Changes to the `docs` repository MUST happen through pull requests. Changes to memory MAY be lighter-weight, but MUST remain versioned in git. -- **No cross-project bleed.** An agent working in one organization MUST NOT apply another organization's standards or memory unless the current task explicitly asks for cross-organization work. -- **Traceable memory.** Memory entries SHOULD identify the context they came from and SHOULD be short, factual, and linked to the relevant issue, pull request, document, or repository when one exists. +- **Reviewed knowledge changes.** Changes to the `docs` repository MUST happen through pull requests. +- **No cross-project bleed.** An agent working in one organization MUST NOT apply another organization's standards unless the current task explicitly asks for cross-organization work. ## Success criteria -- An agent working in `github.com/PSModule/` reads PSModule docs and memory, not another organization's rules. -- An agent working in `github.com/MSXOrg/` resolves `github.com/MSXOrg/docs` and `github.com/MSXOrg/memory` as the canonical project context. -- An agent working in `//` for any adopting organization resolves `//docs` and `//memory` as the canonical project context, with no change to the framework. -- A new product repository can adopt the framework by adding a router and the client routes that reach it, without copying standards or memory pages. +- An agent working in `github.com/PSModule/` reads PSModule docs, not another organization's rules. +- An agent working in `github.com/MSXOrg/` resolves `github.com/MSXOrg/docs` as the canonical project context. +- An agent working in `//` for any adopting organization resolves `//docs` as the canonical project context, with no change to the framework. +- A new product repository can adopt the framework by adding a router and the client routes that reach it, without copying standards pages. - An agent reads the repository's own README and CONTRIBUTING before it reads an organization standard, and still applies the organization standard when the two disagree. -- A human can start at `docs/index.md` or `memory/index.md` and navigate to the same context an agent uses. - A human or agent can follow `docs/index.md` → Ways of Working → Workflow → the current stage procedure without knowing a file path in advance. - A prompt such as `Review this PR ` reaches the Review procedure directly, while `Make this issue ` reaches Define, without a parallel process definition. - A missing, dirty, locally ahead, diverged, wrong-branch, or unreachable canonical context repository stops discovery before any context index is read. - A working checkout of a `docs` repository present on disk is not read as canonical context, and a reader can tell a current checkout from a stale one before trusting either. - Updating a standard in `docs` changes the canonical guidance without editing every repository. -- Capturing a recurring lesson in `memory` makes it available to later agents working in the same organization. ## Context resolution contract @@ -108,15 +99,13 @@ The framework uses this normative reading order: 6. **Path-scoped repository rules** — local rules that apply to the files being read, generated, reviewed, or edited. 7. **Organization documentation** — the `docs` repository for the resolved organization: start at `docs/index.md`, traverse to Ways of Working and Workflow, resolve the current stage, then load the relevant standards, specs, and designs. 8. **Inherited ecosystem documentation** — where the organization inherits from a broader standard set, the layer it inherits from. -9. **Organization memory** — start at `memory/index.md`, then load relevant lessons, gotchas, and active context. -10. **Current task context** — issue, pull request, prompt, branch, diff, diagnostics, terminal output, and open files; use these artifacts to re-evaluate the stage after each handoff. +9. **Current task context** — issue, pull request, prompt, branch, diff, diagnostics, terminal output, and open files; use these artifacts to re-evaluate the stage after each handoff. -This is the order in which context is **read**, nearest first. It is not the order in which conflicts are **resolved**. A repository-local file MAY refine a standard but MUST NOT contradict it unless that standard explicitly allows a local exception; an organization standard governs its own repositories and MAY adjust an inherited ecosystem default for them; and memory MUST NOT override documentation. +This is the order in which context is **read**, nearest first. It is not the order in which conflicts are **resolved**. A repository-local file MAY refine a standard but MUST NOT contradict it unless that standard explicitly allows a local exception; an organization standard governs its own repositories and MAY adjust an inherited ecosystem default for them. ## Where this connects - [Design](design.md) — how these requirements are delivered. -- [Memory Repository Template](memory-template.md) — the concrete scaffold every organization's canonical `memory` repository instantiates. - [MCP Servers](mcp-servers.md) — how one logical tool layer is declared across runtimes. - [Runtime Integration](runtime-integration.md) — what a runtime supplies to be supported, and why process is never part of it. - [Plugin Distribution](plugin-distribution.md) — how named intents stay pointers to documentation. diff --git a/src/docs/Capabilities/index.md b/src/docs/Capabilities/index.md index 75d7ed6..b3b57f5 100644 --- a/src/docs/Capabilities/index.md +++ b/src/docs/Capabilities/index.md @@ -28,7 +28,7 @@ the same spec-and-design shape as any other capability. | [Deployment](deployment/index.md) | How a change to managed resources is approved together with its effect and deployed exactly as approved — one spec, and one design for each combination of deploying a service provider from a CI/CD platform. | | [VS Code Extension Framework](vscode-extension-framework/index.md) | How a VS Code extension is built, tested, versioned, packaged, and published — one GitHub-native pipeline, opt-in from a template and a single settings file. | | [PowerShell on GitHub](powershell-on-github/index.md) | How we make GitHub a first-class platform for PowerShell through reusable modules, actions, and capability gaps we close over time. | -| [Agentic Development](agentic-development/index.md) | The framework for org-scoped docs and memory repositories that give agents project-specific standards, working knowledge, and behavior. | +| [Agentic Development](agentic-development/index.md) | The framework for org-scoped documentation that gives agents project-specific standards and behavior. | diff --git a/src/docs/Capabilities/repository-governance/design-types.md b/src/docs/Capabilities/repository-governance/design-types.md index 665a21d..bbaa789 100644 --- a/src/docs/Capabilities/repository-governance/design-types.md +++ b/src/docs/Capabilities/repository-governance/design-types.md @@ -108,24 +108,6 @@ product — MAY carry a weaker review gate than a repository shipping executable code, because its build check verifies more of what could break. Whether it does is an organization decision ([FR12](spec.md#the-review-gate)). -### Memory - -Declares that the repository is an [agent memory -store](../agentic-development/memory-template.md): append-mostly, written by -agents in small commits, and read at the start of a session. - -| | | -| --- | --- | -| Branch model | None of its own | -| Adjusts | The pull-request requirement, which MUST NOT apply — memory is written by direct commit | - -Memory removes only that one obligation. Its protected branches still reject -deletion and force-pushes, its required checks and automated review still apply, -and merged pull-request branches still use the repository-level cleanup setting. -This targeted subtraction is why the pull-request gate is written as an exclusion -([filter by -exclusion](../../Ways-of-Working/Repository-Type-Property.md#filter-by-exclusion-not-by-inclusion)). - ## The exemption type ### Unmanaged @@ -162,7 +144,6 @@ in is not. | Infrastructure **+** Docs | Promotion flow, plus the documentation-build check on both protected branches | | Infrastructure **+** Artifact | Promotion flow; the artifact history rule applies to merges into the integration branch, and the promotion merge remains a merge commit | | Docs alone | Standard branch model by default, plus the documentation-build check | -| Memory | Baseline applied except the pull-request requirement | | Unmanaged | No baseline; the recorded reason applies | Precedence, stated once: diff --git a/src/docs/Ways-of-Working/Documentation-Model.md b/src/docs/Ways-of-Working/Documentation-Model.md index 4a686af..6f53dbb 100644 --- a/src/docs/Ways-of-Working/Documentation-Model.md +++ b/src/docs/Ways-of-Working/Documentation-Model.md @@ -199,8 +199,7 @@ The artifact tiers provide the second classification: This maps the useful reader needs behind Diataxis without imposing a second, parallel taxonomy in paths or front matter. A page has one home under its subject and links to adjacent artifacts rather than being duplicated across -quadrants. [Document architecture and memory boundaries](../Capabilities/agentic-development/decisions/document-architecture-and-memory-boundaries.md) -records that decision and the corresponding OKF and memory boundaries. +quadrants. ## For humans and agents diff --git a/src/docs/Ways-of-Working/Git-Worktrees.md b/src/docs/Ways-of-Working/Git-Worktrees.md index da5b0fd..7cea80f 100644 --- a/src/docs/Ways-of-Working/Git-Worktrees.md +++ b/src/docs/Ways-of-Working/Git-Worktrees.md @@ -42,7 +42,7 @@ In a single ordinary clone the opposite is forced: one branch checked out at a t - **`/`** — the canonical default-branch worktree. Kept clean and exactly synchronized for reading, diffing, and comparisons. Never directly committed to. - **`-/`** — one worktree folder per repository-delivery Task or Bug in flight, named by issue number and a short slug. The folder is a concise local path; its branch uses the required `/-` name, so the two names do not need to match. -For the central MSXOrg context, this becomes `~/.msxorg/docs.git` plus the readable `~/.msxorg/docs` main worktree. Memory remains a simple checkout at `~/.msxorg/memory`. Each GitHub organization uses its own organization-named root, such as `~/.psmodule` for PSModule. +For the central MSXOrg context, this becomes `~/.msxorg/docs.git` plus the readable `~/.msxorg/docs` main worktree. Each GitHub organization uses its own organization-named root, such as `~/.psmodule` for PSModule. ## Remotes diff --git a/src/docs/Ways-of-Working/Repository-Standard.md b/src/docs/Ways-of-Working/Repository-Standard.md index f374ffe..4ce70fa 100644 --- a/src/docs/Ways-of-Working/Repository-Standard.md +++ b/src/docs/Ways-of-Working/Repository-Standard.md @@ -26,7 +26,7 @@ discoverability minimum defined below instead. | `README.md` | Acts as the repository start page: purpose, value, access, first mental model, and where to go next. | | `LICENSE` | States the legal terms for reuse and redistribution. | | `.github/CONTRIBUTING.md` | Explains how to contribute, including how the organization defaults and central pull request template apply. | -| `AGENTS.md` and its client routes | Route every agent runtime from this repository's own files outward to the initiative and central documentation, then to memory. [Agentic Development](../Capabilities/agentic-development/design.md#client-behavior) names the files and the path each one sits at. | +| `AGENTS.md` and its client routes | Route every agent runtime from this repository's own files outward to the initiative and central documentation. [Agentic Development](../Capabilities/agentic-development/design.md#client-behavior) names the files and the path each one sits at. | | `.github/dependabot.yml` | Configures platform-native dependency-update pull requests for supported ecosystems. The `github-actions` ecosystem is expected in virtually every repository; an unsupported ecosystem follows the centrally managed exception path rather than a repository-local updater. | | `.github/CODEOWNERS` | Routes reviews to responsible owners. | | `.gitattributes` | Normalizes line endings and declares text/binary handling so the repository can be developed and built consistently on Linux, macOS, and Windows. | @@ -53,7 +53,6 @@ stated below, not for the governed baseline. | **Artifact** | The artifact's own manifest or metadata file — whatever declares its identity to the ecosystem it publishes into — and a changelog where the ecosystem expects one rather than reading [GitHub Releases](../Capabilities/release-management/design-publishing-targets.md). | | **Infrastructure** | Documentation of each environment the repository deploys to and how a change reaches it, plus the promotion automation the [promotion flow](../Capabilities/repository-governance/design-types.md#infrastructure) requires. | | **Docs** | The documentation source root and the build configuration the documentation-build check runs. | -| **Memory** | The structure documented by the [memory repository template](../Capabilities/agentic-development/memory-template.md). | | **Unmanaged** | Nothing — but the exemption does not extend to discoverability: `README.md`, `.github/CONTRIBUTING.md`, and the agent router remain required, because a repository nobody governs is still a repository someone will open. | The set a governed repository is audited against is the mandatory set plus the diff --git a/src/docs/Ways-of-Working/Repository-Type-Property.md b/src/docs/Ways-of-Working/Repository-Type-Property.md index d8d1971..feeb764 100644 --- a/src/docs/Ways-of-Working/Repository-Type-Property.md +++ b/src/docs/Ways-of-Working/Repository-Type-Property.md @@ -84,7 +84,7 @@ the values that should be covered. ```json "repository_property": { "include": [], - "exclude": [{ "name": "Type", "source": "custom", "property_values": ["Memory"] }] + "exclude": [{ "name": "Type", "source": "custom", "property_values": ["Unmanaged"] }] } ``` @@ -146,8 +146,8 @@ examples and must not be copied into a new organization without migration: | Organization | `Type` allowed values | Notes | | --- | --- | --- | -| `MSXOrg` | `Docs`, `Memory`, `VSCodeExtension`, `Other` | Legacy values that predate the canonical taxonomy. | -| `PSModule` | `Action`, `Archive`, `Docs`, `Framework`, `FunctionApp`, `Memory`, `Module`, `Other`, `Template`, `Workflow` | Legacy values that predate the canonical taxonomy. | +| `MSXOrg` | `Docs`, `VSCodeExtension`, `Other` | Legacy values that predate the canonical taxonomy. | +| `PSModule` | `Action`, `Archive`, `Docs`, `Framework`, `FunctionApp`, `Module`, `Other`, `Template`, `Workflow` | Legacy values that predate the canonical taxonomy. | An organization's canonical list is shaped by what it builds, but it has the taxonomy defined by [Repository Types](../Capabilities/repository-governance/design-types.md): @@ -155,12 +155,6 @@ one branch model (explicit or defaulted), any layering values, and `Unmanaged` a the sole exemption. A migration maps historical values into that taxonomy before the canonical `Type` property becomes authoritative. -Where a historical value maps to Memory, repositories with `Type: Memory` — the -[Memory Repository Template](../Capabilities/agentic-development/memory-template.md)'s -no-PR, direct-commit-to-`main` repositories — are excluded from the org-wide pull-request- -required ruleset. The exclusion applies only to that requirement; Memory retains -the rest of the governed baseline. - ## Where this connects - [Repository Governance](../Capabilities/repository-governance/spec.md) — the framework this @@ -172,6 +166,3 @@ the rest of the governed baseline. rules attached to them. - [Repository Standard](Repository-Standard.md) — the mandatory/type-specific/ repository-specific file-set distinction that `Type` also drives over time. -- [Memory Repository Template](../Capabilities/agentic-development/memory-template.md) — the - concrete repository type whose no-PR workflow motivated excluding `Type: Memory` from the - pull-request-required ruleset in both current organizations. diff --git a/src/zensical.toml b/src/zensical.toml index 1612877..43d7dad 100644 --- a/src/zensical.toml +++ b/src/zensical.toml @@ -168,7 +168,6 @@ nav = [ "Capabilities/agentic-development/index.md", {"Spec" = "Capabilities/agentic-development/spec.md"}, {"Design" = "Capabilities/agentic-development/design.md"}, - {"Memory Repository Template" = "Capabilities/agentic-development/memory-template.md"}, {"MCP Servers" = "Capabilities/agentic-development/mcp-servers.md"}, {"Runtime Integration" = "Capabilities/agentic-development/runtime-integration.md"}, {"Plugin Distribution" = "Capabilities/agentic-development/plugin-distribution.md"}, @@ -178,7 +177,6 @@ nav = [ {"Conformance" = "Capabilities/agentic-development/conformance.md"}, {"Decisions" = [ "Capabilities/agentic-development/decisions/index.md", - {"Document Architecture and Memory Boundaries" = "Capabilities/agentic-development/decisions/document-architecture-and-memory-boundaries.md"}, ]}, ]}, ]}, diff --git a/tests/Initialize-MsxWorkspace.Tests.ps1 b/tests/Initialize-MsxWorkspace.Tests.ps1 index 65393f1..982b1b3 100644 --- a/tests/Initialize-MsxWorkspace.Tests.ps1 +++ b/tests/Initialize-MsxWorkspace.Tests.ps1 @@ -1,785 +1,61 @@ #Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '6.0.0'; MaximumVersion = '6.*' } -Describe 'Initialize-MsxWorkspace context freshness' { +Describe 'Initialize-MsxWorkspace documentation bootstrap' { BeforeAll { - $script:bootstrap = Join-Path $PSScriptRoot '../bootstrap/Initialize-MsxWorkspace.ps1' - $script:agentTemplate = Join-Path $PSScriptRoot '../bootstrap/AGENTS.template.md' - $script:bootstrapReadme = Join-Path $PSScriptRoot '../bootstrap/README.md' + $script:bootstrap = (Resolve-Path (Join-Path $PSScriptRoot '../bootstrap/Initialize-MsxWorkspace.ps1')).Path $script:pwsh = (Get-Process -Id $PID).Path - function Invoke-Git { - param( - [Parameter()] - [string] $WorkingDirectory, + function Invoke-Bootstrap { + param([Parameter(Mandatory)] [string] $ProjectText) - [Parameter(Mandatory)] - [string[]] $Arguments - ) - - $output = if ($WorkingDirectory) { - & git -C $WorkingDirectory @Arguments 2>&1 - } else { - & git @Arguments 2>&1 - } - if ($LASTEXITCODE -ne 0) { - throw "git $($Arguments -join ' ') failed in '$WorkingDirectory': $($output | Out-String)" - } - return $output - } - - function Add-TestCommit { - param( - [Parameter(Mandatory)] - [string] $Repository, - - [Parameter(Mandatory)] - [string] $Name - ) - - Add-Content -LiteralPath (Join-Path $Repository 'context.txt') -Value $Name - Invoke-Git -WorkingDirectory $Repository -Arguments @('add', 'context.txt') | Out-Null - Invoke-Git -WorkingDirectory $Repository -Arguments @('commit', '--quiet', '-m', $Name) | Out-Null - } - - function New-ContextFixture { - [CmdletBinding(SupportsShouldProcess)] - param() - - $root = Join-Path ([IO.Path]::GetTempPath()) "msx-bootstrap-$([guid]::NewGuid().ToString('N'))" - if (-not $PSCmdlet.ShouldProcess($root, 'Create context fixture')) { - return - } - $workspace = Join-Path $root 'workspace' - $remotes = Join-Path $root 'remotes' - $writers = Join-Path $root 'writers' - New-Item -ItemType Directory -Path $workspace, $remotes, $writers -Force | Out-Null - - $writerMap = @{} - $remoteMap = @{} - foreach ($name in @('docs', 'memory')) { - $remote = Join-Path $remotes "$name.git" - $writer = Join-Path $writers $name - $checkout = Join-Path $workspace $name - - Invoke-Git -Arguments @('init', '--bare', '--quiet', '--initial-branch=main', $remote) | Out-Null - Invoke-Git -Arguments @('clone', '--quiet', $remote, $writer) | Out-Null - Invoke-Git -WorkingDirectory $writer -Arguments @('config', 'user.name', 'Fixture Writer') | Out-Null - Invoke-Git -WorkingDirectory $writer -Arguments @('config', 'user.email', 'fixture@example.invalid') | Out-Null - Set-Content -LiteralPath (Join-Path $writer 'context.txt') -Value "$name context" - if ($name -eq 'docs') { - $bootstrapDirectory = Join-Path $writer 'bootstrap' - New-Item -ItemType Directory -Path $bootstrapDirectory | Out-Null - Copy-Item -LiteralPath $script:bootstrap -Destination $bootstrapDirectory - } - Invoke-Git -WorkingDirectory $writer -Arguments @('add', 'context.txt') | Out-Null - if ($name -eq 'docs') { - Invoke-Git -WorkingDirectory $writer -Arguments @('add', 'bootstrap/Initialize-MsxWorkspace.ps1') | Out-Null - } - Invoke-Git -WorkingDirectory $writer -Arguments @('commit', '--quiet', '-m', "Initialize $name") | Out-Null - Invoke-Git -WorkingDirectory $writer -Arguments @('push', '--quiet', '--set-upstream', 'origin', 'main') | Out-Null - Invoke-Git -Arguments @('clone', '--quiet', $remote, $checkout) | Out-Null - Invoke-Git -WorkingDirectory $checkout -Arguments @('config', 'user.name', 'Fixture Local') | Out-Null - Invoke-Git -WorkingDirectory $checkout -Arguments @('config', 'user.email', 'fixture-local@example.invalid') | Out-Null - $writerMap[$name] = $writer - $remoteMap[$name] = $remote - } - - return [pscustomobject]@{ - Root = $root - Workspace = $workspace - Writers = $writerMap - Remotes = $remoteMap - Docs = Join-Path $workspace 'docs' - Memory = Join-Path $workspace 'memory' - } - } - - function Invoke-BootstrapFixture { - param([Parameter(Mandatory)] $Fixture) - - $runner = Join-Path $Fixture.Root 'invoke-bootstrap.ps1' - $bootstrap = $script:bootstrap.Replace("'", "''") - $workspace = $Fixture.Workspace.Replace("'", "''") - $docsRemote = $Fixture.Remotes.docs.Replace("'", "''") - $memoryRemote = $Fixture.Remotes.memory.Replace("'", "''") + $runner = Join-Path $fixtureRoot 'run.ps1' @" -`$projects = @( - @{ - Name = 'Fixture' - Path = '' - DocsUrl = '$docsRemote' - MemoryUrl = '$memoryRemote' - } -) -& '$bootstrap' -Root '$workspace' -Project `$projects -UserName 'Fixture User' -UserEmail 'fixture@example.invalid' +`$projects = $ProjectText +& '$bootstrap' -Root '$workspace' -Project `$projects -UserName 'Fixture' -UserEmail 'fixture@example.invalid' exit `$LASTEXITCODE -"@ | Set-Content -LiteralPath $runner - $output = & $script:pwsh -NoProfile -File $runner 2>&1 | Out-String - - return [pscustomobject]@{ - ExitCode = $LASTEXITCODE - Output = $output - } - } - - function Invoke-BootstrapSeed { - param( - [Parameter(Mandatory)] - $Fixture, - - [Parameter(Mandatory)] - [string] $MarkdownPath, - - [Parameter(Mandatory)] - [string] $Workspace - ) - - $markdown = Get-Content -LiteralPath $MarkdownPath -Raw - $match = [regex]::Match($markdown, '(?s)```powershell\r?\n(.*?)\r?\n```') - if (-not $match.Success) { - throw "No PowerShell seed block found in '$MarkdownPath'." - } - $runner = Join-Path $Fixture.Root "seed-$([IO.Path]::GetFileNameWithoutExtension($MarkdownPath)).ps1" - Set-Content -LiteralPath $runner -Value $match.Groups[1].Value - $previousRoot = $env:MSX_WORKSPACE_ROOT - $previousDocs = $env:MSX_DOCS_URL - $previousMemory = $env:MSX_MEMORY_URL - try { - $env:MSX_WORKSPACE_ROOT = $Workspace - $env:MSX_DOCS_URL = $Fixture.Remotes.docs - $env:MSX_MEMORY_URL = $Fixture.Remotes.memory - $output = & $script:pwsh -NoProfile -File $runner 2>&1 | Out-String - return [pscustomobject]@{ ExitCode = $LASTEXITCODE; Output = $output } - } finally { - $env:MSX_WORKSPACE_ROOT = $previousRoot - $env:MSX_DOCS_URL = $previousDocs - $env:MSX_MEMORY_URL = $previousMemory - } +"@ | Set-Content $runner + & $script:pwsh -NoProfile -File $runner 2>&1 } } BeforeEach { - $fixture = New-ContextFixture - $fixture | Should -Not -BeNullOrEmpty + $fixtureRoot = Join-Path ([IO.Path]::GetTempPath()) "msx-bootstrap-$([guid]::NewGuid().ToString('N'))" + $remote = Join-Path $fixtureRoot 'docs.git' + $writer = Join-Path $fixtureRoot 'writer' + $workspace = Join-Path $fixtureRoot 'workspace' + New-Item -ItemType Directory -Path $fixtureRoot -Force | Out-Null + & git init --bare --quiet --initial-branch=main $remote + & git clone --quiet $remote $writer + & git -C $writer config user.name 'Fixture Writer' + & git -C $writer config user.email 'fixture@example.invalid' + New-Item -ItemType Directory -Path (Join-Path $writer 'bootstrap') | Out-Null + Copy-Item $script:bootstrap (Join-Path $writer 'bootstrap/Initialize-MsxWorkspace.ps1') + Set-Content (Join-Path $writer 'context.txt') 'docs context' + & git -C $writer add . + & git -C $writer commit --quiet -m 'Initialize docs' + & git -C $writer push --quiet --set-upstream origin main + $script:remote = $remote + $script:workspace = $workspace } AfterEach { - if ($fixture -and (Test-Path -LiteralPath $fixture.Root)) { - Remove-Item -LiteralPath $fixture.Root -Recurse -Force + if (Test-Path $fixtureRoot) { + Remove-Item $fixtureRoot -Recurse -Force } } - It 'fast-forwards a clean behind checkout to the exact remote head' { - Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('branch', 'local-topic') | Out-Null - Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('tag', 'local-tag') | Out-Null - $topicHead = (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'local-topic')).Trim() - $tagHead = (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'local-tag')).Trim() - Add-TestCommit -Repository $fixture.Writers.docs -Name 'Advance docs' - Invoke-Git -WorkingDirectory $fixture.Writers.docs -Arguments @('push', '--quiet') | Out-Null - Add-TestCommit -Repository $fixture.Writers.memory -Name 'Advance memory' - Invoke-Git -WorkingDirectory $fixture.Writers.memory -Arguments @('push', '--quiet') | Out-Null - $docsHead = (Invoke-Git -WorkingDirectory $fixture.Writers.docs -Arguments @('rev-parse', 'HEAD')).Trim() - $memoryHead = (Invoke-Git -WorkingDirectory $fixture.Writers.memory -Arguments @('rev-parse', 'HEAD')).Trim() - - $result = Invoke-BootstrapFixture -Fixture $fixture - - $result.ExitCode | Should -Be 0 -Because $result.Output - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() | Should -BeExactly $docsHead - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'origin/main')).Trim() | Should -BeExactly $docsHead - (Invoke-Git -WorkingDirectory $fixture.Memory -Arguments @('rev-parse', 'HEAD')).Trim() | Should -BeExactly $memoryHead - (Invoke-Git -WorkingDirectory $fixture.Memory -Arguments @('rev-parse', 'origin/main')).Trim() | Should -BeExactly $memoryHead - Test-Path -LiteralPath (Join-Path $fixture.Docs '.git') -PathType Leaf | Should -BeTrue - Test-Path -LiteralPath (Join-Path $fixture.Workspace 'docs.git') -PathType Container | Should -BeTrue - (Invoke-Git -Arguments @("--git-dir=$(Join-Path $fixture.Workspace 'docs.git')", 'rev-parse', '--is-bare-repository')).Trim() | - Should -BeExactly 'true' - (Invoke-Git -Arguments @("--git-dir=$(Join-Path $fixture.Workspace 'docs.git')", 'rev-parse', 'local-topic')).Trim() | - Should -BeExactly $topicHead - (Invoke-Git -Arguments @("--git-dir=$(Join-Path $fixture.Workspace 'docs.git')", 'rev-parse', 'local-tag')).Trim() | - Should -BeExactly $tagHead - Test-Path -LiteralPath (Join-Path $fixture.Workspace 'docs.simple-clone-backup') | Should -BeTrue - Test-Path -LiteralPath (Join-Path $fixture.Memory '.git') -PathType Container | Should -BeTrue - (Invoke-BootstrapFixture -Fixture $fixture).ExitCode | Should -Be 0 - } - - It 'rejects a dirty checkout without updating it' { - Set-Content -LiteralPath (Join-Path $fixture.Docs 'dirty.txt') -Value 'uncommitted' - $before = (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() - - $result = Invoke-BootstrapFixture -Fixture $fixture - - $result.ExitCode | Should -Not -Be 0 - $result.Output | Should -Match 'uncommitted changes' - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() | Should -BeExactly $before - } - - It 'rejects a locally ahead checkout without stale fallback' { - Add-TestCommit -Repository $fixture.Docs -Name 'Local only' - $before = (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() - - $result = Invoke-BootstrapFixture -Fixture $fixture - - $result.ExitCode | Should -Not -Be 0 - $result.Output | Should -Match 'not exactly synchronized' - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() | Should -BeExactly $before - } - - It 'rejects diverged history without updating the checkout' { - Add-TestCommit -Repository $fixture.Docs -Name 'Local divergence' - $before = (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() - Add-TestCommit -Repository $fixture.Writers.docs -Name 'Remote divergence' - Invoke-Git -WorkingDirectory $fixture.Writers.docs -Arguments @('push', '--quiet') | Out-Null - - $result = Invoke-BootstrapFixture -Fixture $fixture - - $result.ExitCode | Should -Not -Be 0 - $result.Output | Should -Match 'Could not fast-forward' - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() | Should -BeExactly $before - } - - It 'rejects a checkout on a non-default branch' { - Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('switch', '--quiet', '-c', 'topic') | Out-Null - - $result = Invoke-BootstrapFixture -Fixture $fixture - - $result.ExitCode | Should -Not -Be 0 - $result.Output | Should -Match "not the default branch 'main'" - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('branch', '--show-current')).Trim() | Should -BeExactly 'topic' - } - - It 'rejects an unreachable remote without using local context' { - $missing = Join-Path $fixture.Root 'missing.git' - Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('remote', 'set-url', 'origin', $missing) | Out-Null - $fixture.Remotes.docs = $missing - $before = (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() - - $result = Invoke-BootstrapFixture -Fixture $fixture - - $result.ExitCode | Should -Not -Be 0 - $result.Output | Should -Match 'git fetch failed' - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() | Should -BeExactly $before - } - - It 'rejects a non-canonical origin before fetching context' { - Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @( - 'remote', - 'set-url', - 'origin', - $fixture.Remotes.memory - ) | Out-Null - $before = (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() - - $result = Invoke-BootstrapFixture -Fixture $fixture - - $result.ExitCode | Should -Not -Be 0 - $result.Output | Should -Match 'not canonical' - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly $before - } - - It 'rejects a non-canonical bare docs origin before mutation' { - (Invoke-BootstrapFixture -Fixture $fixture).ExitCode | Should -Be 0 - $backing = Join-Path $fixture.Workspace 'docs.git' - Invoke-Git -Arguments @( - "--git-dir=$backing", - 'remote', - 'set-url', - 'origin', - $fixture.Remotes.memory - ) | Out-Null - $before = (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() - - $result = Invoke-BootstrapFixture -Fixture $fixture - - $result.ExitCode | Should -Not -Be 0 - $result.Output | Should -Match 'not canonical' - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly $before - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('status', '--porcelain')) | - Should -BeNullOrEmpty - } - - It 'rejects a non-canonical memory origin before docs migration' { - Invoke-Git -WorkingDirectory $fixture.Memory -Arguments @( - 'remote', - 'set-url', - 'origin', - $fixture.Remotes.docs - ) | Out-Null - $docsBefore = (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() - $memoryBefore = (Invoke-Git -WorkingDirectory $fixture.Memory -Arguments @('rev-parse', 'HEAD')).Trim() - - $result = Invoke-BootstrapFixture -Fixture $fixture + It 'creates a bare backing repository and documentation worktree' { + Invoke-Bootstrap -ProjectText "@(@{ Name = 'Fixture'; Path = ''; DocsUrl = '$remote' })" | Out-Null - $result.ExitCode | Should -Not -Be 0 - $result.Output | Should -Match 'not canonical' - Test-Path -LiteralPath (Join-Path $fixture.Workspace 'docs.git') | Should -BeFalse - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly $docsBefore - (Invoke-Git -WorkingDirectory $fixture.Memory -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly $memoryBefore - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('status', '--porcelain')) | - Should -BeNullOrEmpty - (Invoke-Git -WorkingDirectory $fixture.Memory -Arguments @('status', '--porcelain')) | - Should -BeNullOrEmpty + $LASTEXITCODE | Should -Be 0 + Test-Path (Join-Path $workspace 'docs.git') | Should -BeTrue + Test-Path (Join-Path $workspace 'docs/.git') | Should -BeTrue + Test-Path (Join-Path $workspace 'docs/context.txt') | Should -BeTrue + Test-Path (Join-Path $workspace 'memory') | Should -BeFalse } - It 'rejects a memory worktree before docs migration' { - Remove-Item -LiteralPath $fixture.Memory -Recurse -Force - $memoryBacking = Join-Path $fixture.Root 'memory-backing.git' - Invoke-Git -Arguments @('clone', '--bare', '--quiet', $fixture.Remotes.memory, $memoryBacking) | Out-Null - Invoke-Git -Arguments @( - "--git-dir=$memoryBacking", - 'worktree', - 'add', - '--quiet', - $fixture.Memory, - 'main' - ) | Out-Null - $docsBefore = (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() - $memoryBefore = (Invoke-Git -WorkingDirectory $fixture.Memory -Arguments @('rev-parse', 'HEAD')).Trim() - - $result = Invoke-BootstrapFixture -Fixture $fixture - - $result.ExitCode | Should -Not -Be 0 - $result.Output | Should -Match 'memory requires a simple checkout' - Test-Path -LiteralPath (Join-Path $fixture.Workspace 'docs.git') | Should -BeFalse - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly $docsBefore - (Invoke-Git -WorkingDirectory $fixture.Memory -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly $memoryBefore - } - - It 'installs additional project context through plug-in coordinates' { - $runner = Join-Path $fixture.Root 'invoke-project-bootstrap.ps1' - $bootstrap = $script:bootstrap.Replace("'", "''") - $workspace = $fixture.Workspace.Replace("'", "''") - $docsRemote = $fixture.Remotes.docs.Replace("'", "''") - $memoryRemote = $fixture.Remotes.memory.Replace("'", "''") - @" -`$projects = @( - @{ - Name = 'MSXOrg' - Path = '' - DocsUrl = '$docsRemote' - MemoryUrl = '$memoryRemote' - } - @{ - Name = 'Project' - Path = './projects/Project/' - DocsUrl = '$docsRemote' - MemoryUrl = '$memoryRemote' - } -) -& '$bootstrap' -Root '$workspace' -Project `$projects -UserName 'Fixture User' -UserEmail 'fixture@example.invalid' -exit `$LASTEXITCODE -"@ | Set-Content -LiteralPath $runner - - $output = & $script:pwsh -NoProfile -File $runner 2>&1 | Out-String - - $LASTEXITCODE | Should -Be 0 -Because $output - $projectDocs = Join-Path $fixture.Workspace 'projects/Project/docs' - $projectMemory = Join-Path $fixture.Workspace 'projects/Project/memory' - Test-Path -LiteralPath (Join-Path $projectDocs '.git') | Should -BeTrue - Test-Path -LiteralPath (Join-Path $projectMemory '.git') | Should -BeTrue - Test-Path -LiteralPath (Join-Path $fixture.Workspace 'projects/Project/docs.git') | Should -BeTrue - (Invoke-Git -Arguments @( - "--git-dir=$(Join-Path $fixture.Workspace 'projects/Project/docs.git')", - 'rev-parse', - '--is-bare-repository' - )).Trim() | Should -BeExactly 'true' - (Invoke-Git -WorkingDirectory $projectDocs -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly (Invoke-Git -WorkingDirectory $fixture.Writers.docs -Arguments @('rev-parse', 'HEAD')).Trim() - (Invoke-Git -WorkingDirectory $projectMemory -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly (Invoke-Git -WorkingDirectory $fixture.Writers.memory -Arguments @('rev-parse', 'HEAD')).Trim() - } - - It 'rejects duplicate project paths after normalization' { - $runner = Join-Path $fixture.Root 'invoke-duplicate-bootstrap.ps1' - $bootstrap = $script:bootstrap.Replace("'", "''") - $workspace = $fixture.Workspace.Replace("'", "''") - $docsRemote = $fixture.Remotes.docs.Replace("'", "''") - $memoryRemote = $fixture.Remotes.memory.Replace("'", "''") - @" -`$projects = @( - @{ - Name = 'One' - Path = '' - DocsUrl = '$docsRemote' - MemoryUrl = '$memoryRemote' - } - @{ - Name = 'Two' - Path = '.' - DocsUrl = '$docsRemote' - MemoryUrl = '$memoryRemote' - } -) -& '$bootstrap' -Root '$workspace' -Project `$projects -UserName 'Fixture User' -UserEmail 'fixture@example.invalid' -exit `$LASTEXITCODE -"@ | Set-Content -LiteralPath $runner - - $output = & $script:pwsh -NoProfile -File $runner 2>&1 | Out-String - - $LASTEXITCODE | Should -Not -Be 0 - $output | Should -Match 'workspace paths overlap' - } - - It 'rejects duplicate project names before mutation' -ForEach @( - @{ SecondPath = '' } - @{ SecondPath = 'docs' } - ) { - $beforeDocs = (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() - $beforeMemory = (Invoke-Git -WorkingDirectory $fixture.Memory -Arguments @('rev-parse', 'HEAD')).Trim() - $runner = Join-Path $fixture.Root "invoke-duplicate-name-$($SecondPath -replace '[^A-Za-z0-9]', '-').ps1" - $bootstrap = $script:bootstrap.Replace("'", "''") - $workspace = $fixture.Workspace.Replace("'", "''") - $docsRemote = $fixture.Remotes.docs.Replace("'", "''") - $memoryRemote = $fixture.Remotes.memory.Replace("'", "''") - @" -`$projects = @( - @{ - Name = 'Duplicate' - Path = '' - DocsUrl = '$docsRemote' - MemoryUrl = '$memoryRemote' - } - @{ - Name = 'Duplicate' - Path = '$SecondPath' - DocsUrl = '$docsRemote' - MemoryUrl = '$memoryRemote' - } -) -& '$bootstrap' -Root '$workspace' -Project `$projects -UserName 'Fixture User' -UserEmail 'fixture@example.invalid' -exit `$LASTEXITCODE -"@ | Set-Content -LiteralPath $runner - - $output = & $script:pwsh -NoProfile -File $runner 2>&1 | Out-String - - $LASTEXITCODE | Should -Not -Be 0 - $output | Should -Match 'unique names' - Test-Path -LiteralPath (Join-Path $fixture.Workspace 'docs.git') | Should -BeFalse - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly $beforeDocs - (Invoke-Git -WorkingDirectory $fixture.Memory -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly $beforeMemory - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('status', '--porcelain')) | - Should -BeNullOrEmpty - (Invoke-Git -WorkingDirectory $fixture.Memory -Arguments @('status', '--porcelain')) | - Should -BeNullOrEmpty - } - - It 'rejects project paths overlapping canonical context storage' -ForEach @( - @{ UnsafePath = 'docs' } - @{ UnsafePath = 'docs.git' } - @{ UnsafePath = 'memory' } - @{ UnsafePath = 'docs/child' } - @{ UnsafePath = 'docs.git/child' } - @{ UnsafePath = 'memory/child' } - @{ UnsafePath = 'docs.simple-clone-backup' } - @{ UnsafePath = 'docs.simple-clone-backup/child' } - ) { - $beforeDocs = (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() - $beforeMemory = (Invoke-Git -WorkingDirectory $fixture.Memory -Arguments @('rev-parse', 'HEAD')).Trim() - $safeName = $UnsafePath -replace '[^A-Za-z0-9-]', '-' - $runner = Join-Path $fixture.Root "invoke-overlap-$safeName.ps1" - $bootstrap = $script:bootstrap.Replace("'", "''") - $workspace = $fixture.Workspace.Replace("'", "''") - $docsRemote = $fixture.Remotes.docs.Replace("'", "''") - $memoryRemote = $fixture.Remotes.memory.Replace("'", "''") - @" -`$projects = @( - @{ - Name = 'MSXOrg' - Path = '' - DocsUrl = '$docsRemote' - MemoryUrl = '$memoryRemote' - } - @{ - Name = 'Unsafe' - Path = '$UnsafePath' - DocsUrl = '$docsRemote' - MemoryUrl = '$memoryRemote' - } -) -& '$bootstrap' -Root '$workspace' -Project `$projects -UserName 'Fixture User' -UserEmail 'fixture@example.invalid' -exit `$LASTEXITCODE -"@ | Set-Content -LiteralPath $runner - - $output = & $script:pwsh -NoProfile -File $runner 2>&1 | Out-String - + It 'rejects a project definition that omits documentation coordinates' { + Invoke-Bootstrap -ProjectText "@(@{ Name = 'Fixture'; Path = '' })" | Out-Null $LASTEXITCODE | Should -Not -Be 0 - $output | Should -Match 'workspace paths overlap' - $unsafeRoot = Join-Path $fixture.Workspace $UnsafePath - foreach ($child in @('docs', 'docs.git', 'memory', 'docs.simple-clone-backup')) { - Test-Path -LiteralPath (Join-Path $unsafeRoot $child) | Should -BeFalse - } - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly $beforeDocs - (Invoke-Git -WorkingDirectory $fixture.Memory -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly $beforeMemory - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('status', '--porcelain')) | - Should -BeNullOrEmpty - (Invoke-Git -WorkingDirectory $fixture.Memory -Arguments @('status', '--porcelain')) | - Should -BeNullOrEmpty - } - - It 'rejects overlapping non-empty project roots before mutation' { - $runner = Join-Path $fixture.Root 'invoke-overlapping-roots.ps1' - $bootstrap = $script:bootstrap.Replace("'", "''") - $workspace = $fixture.Workspace.Replace("'", "''") - $docsRemote = $fixture.Remotes.docs.Replace("'", "''") - $memoryRemote = $fixture.Remotes.memory.Replace("'", "''") - @" -`$projects = @( - @{ - Name = 'Parent' - Path = 'projects/Parent' - DocsUrl = '$docsRemote' - MemoryUrl = '$memoryRemote' - } - @{ - Name = 'Child' - Path = 'projects/Parent/Child' - DocsUrl = '$docsRemote' - MemoryUrl = '$memoryRemote' - } -) -& '$bootstrap' -Root '$workspace' -Project `$projects -UserName 'Fixture User' -UserEmail 'fixture@example.invalid' -exit `$LASTEXITCODE -"@ | Set-Content -LiteralPath $runner - - $output = & $script:pwsh -NoProfile -File $runner 2>&1 | Out-String - - $LASTEXITCODE | Should -Not -Be 0 - $output | Should -Match 'workspace paths overlap' - Test-Path -LiteralPath (Join-Path $fixture.Workspace 'projects') | Should -BeFalse - } - - It 'reuses a canonical docs worktree with a legacy bare backing path' { - Remove-Item -LiteralPath $fixture.Docs -Recurse -Force - $legacyBacking = Join-Path $fixture.Root 'legacy-docs-backing.git' - Invoke-Git -Arguments @('clone', '--bare', '--quiet', $fixture.Remotes.docs, $legacyBacking) | Out-Null - Invoke-Git -Arguments @( - "--git-dir=$legacyBacking", - 'config', - '--add', - 'remote.origin.fetch', - '+refs/heads/*:refs/remotes/origin/*' - ) | Out-Null - Invoke-Git -Arguments @("--git-dir=$legacyBacking", 'fetch', '--quiet', 'origin') | Out-Null - Invoke-Git -Arguments @("--git-dir=$legacyBacking", 'worktree', 'add', '--quiet', $fixture.Docs, 'main') | Out-Null - - $result = Invoke-BootstrapFixture -Fixture $fixture - - $result.ExitCode | Should -Be 0 -Because $result.Output - $commonDir = (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @( - 'rev-parse', - '--path-format=absolute', - '--git-common-dir' - )).Trim() - [IO.Path]::GetFullPath($commonDir) | Should -BeExactly ([IO.Path]::GetFullPath($legacyBacking)) - Test-Path -LiteralPath (Join-Path $fixture.Workspace 'docs.git') | Should -BeFalse - } - - It 'installs missing docs as bare backing plus main worktree and memory as a simple clone' { - $emptyRoot = Join-Path $fixture.Root 'empty-workspace' - $runner = Join-Path $fixture.Root 'invoke-empty-bootstrap.ps1' - $bootstrap = $script:bootstrap.Replace("'", "''") - $docsRemote = $fixture.Remotes.docs.Replace("'", "''") - $memoryRemote = $fixture.Remotes.memory.Replace("'", "''") - @" -`$projects = @( - @{ - Name = 'Fixture' - Path = '' - DocsUrl = '$docsRemote' - MemoryUrl = '$memoryRemote' - } -) -& '$bootstrap' -Root '$emptyRoot' -Project `$projects -UserName 'Fixture User' -UserEmail 'fixture@example.invalid' -exit `$LASTEXITCODE -"@ | Set-Content -LiteralPath $runner - - $output = & $script:pwsh -NoProfile -File $runner 2>&1 | Out-String - - $LASTEXITCODE | Should -Be 0 -Because $output - $docs = Join-Path $emptyRoot 'docs' - $backing = Join-Path $emptyRoot 'docs.git' - $memory = Join-Path $emptyRoot 'memory' - Test-Path -LiteralPath (Join-Path $docs '.git') -PathType Leaf | Should -BeTrue - (Invoke-Git -Arguments @("--git-dir=$backing", 'rev-parse', '--is-bare-repository')).Trim() | - Should -BeExactly 'true' - (Invoke-Git -WorkingDirectory $docs -Arguments @('branch', '--show-current')).Trim() | Should -BeExactly 'main' - (Invoke-Git -WorkingDirectory $docs -Arguments @('status', '--porcelain')) | Should -BeNullOrEmpty - (Invoke-Git -WorkingDirectory $docs -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly (Invoke-Git -WorkingDirectory $fixture.Writers.docs -Arguments @('rev-parse', 'HEAD')).Trim() - Test-Path -LiteralPath (Join-Path $memory '.git') -PathType Container | - Should -BeTrue -Because $output - (Invoke-Git -WorkingDirectory $memory -Arguments @('branch', '--show-current')).Trim() | - Should -BeExactly 'main' - (Invoke-Git -WorkingDirectory $memory -Arguments @('status', '--porcelain')) | - Should -BeNullOrEmpty - (Invoke-Git -WorkingDirectory $memory -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly (Invoke-Git -WorkingDirectory $fixture.Writers.memory -Arguments @('rev-parse', 'HEAD')).Trim() - foreach ($repository in @($docs, $memory)) { - (Invoke-Git -WorkingDirectory $repository -Arguments @('config', '--local', 'user.name')).Trim() | - Should -BeExactly 'Fixture User' - (Invoke-Git -WorkingDirectory $repository -Arguments @('config', '--local', 'user.email')).Trim() | - Should -BeExactly 'fixture@example.invalid' - } - $emptyFixture = [pscustomobject]@{ - Root = $fixture.Root - Workspace = $emptyRoot - Remotes = $fixture.Remotes - } - (Invoke-BootstrapFixture -Fixture $emptyFixture).ExitCode | Should -Be 0 - (Invoke-Git -WorkingDirectory $docs -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly (Invoke-Git -WorkingDirectory $fixture.Writers.docs -Arguments @('rev-parse', 'HEAD')).Trim() - (Invoke-Git -WorkingDirectory $memory -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly (Invoke-Git -WorkingDirectory $fixture.Writers.memory -Arguments @('rev-parse', 'HEAD')).Trim() - } - - It 'fast-forwards an existing bare backing before creating its missing main worktree' { - $emptyRoot = Join-Path $fixture.Root 'backing-only-workspace' - New-Item -ItemType Directory -Path $emptyRoot | Out-Null - $backing = Join-Path $emptyRoot 'docs.git' - Invoke-Git -Arguments @('clone', '--bare', '--quiet', $fixture.Remotes.docs, $backing) | Out-Null - Add-TestCommit -Repository $fixture.Writers.docs -Name 'Advance after bare clone' - Invoke-Git -WorkingDirectory $fixture.Writers.docs -Arguments @('push', '--quiet') | Out-Null - $remoteHead = (Invoke-Git -WorkingDirectory $fixture.Writers.docs -Arguments @('rev-parse', 'HEAD')).Trim() - $runner = Join-Path $fixture.Root 'invoke-backing-only-bootstrap.ps1' - $bootstrap = $script:bootstrap.Replace("'", "''") - $docsRemote = $fixture.Remotes.docs.Replace("'", "''") - $memoryRemote = $fixture.Remotes.memory.Replace("'", "''") - @" -`$projects = @( - @{ - Name = 'Fixture' - Path = '' - DocsUrl = '$docsRemote' - MemoryUrl = '$memoryRemote' - } -) -& '$bootstrap' -Root '$emptyRoot' -Project `$projects -UserName 'Fixture User' -UserEmail 'fixture@example.invalid' -exit `$LASTEXITCODE -"@ | Set-Content -LiteralPath $runner - - $output = & $script:pwsh -NoProfile -File $runner 2>&1 | Out-String - - $LASTEXITCODE | Should -Be 0 -Because $output - $docs = Join-Path $emptyRoot 'docs' - (Invoke-Git -WorkingDirectory $docs -Arguments @('rev-parse', 'HEAD')).Trim() | Should -BeExactly $remoteHead - (Invoke-Git -Arguments @("--git-dir=$backing", 'rev-parse', 'main')).Trim() | Should -BeExactly $remoteHead - } - - It 'rolls back a post-move migration failure without changing the simple clone' { - $before = (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() - $runner = Join-Path $fixture.Root 'invoke-failed-migration.ps1' - $bootstrap = $script:bootstrap.Replace("'", "''") - $workspace = $fixture.Workspace.Replace("'", "''") - $docsRemote = $fixture.Remotes.docs.Replace("'", "''") - $memoryRemote = $fixture.Remotes.memory.Replace("'", "''") - @" -`$env:MSX_BOOTSTRAP_TEST_FAIL_AFTER_DOCS_MOVE = '1' -`$projects = @( - @{ - Name = 'Fixture' - Path = '' - DocsUrl = '$docsRemote' - MemoryUrl = '$memoryRemote' - } -) -& '$bootstrap' -Root '$workspace' -Project `$projects -UserName 'Fixture User' -UserEmail 'fixture@example.invalid' -exit `$LASTEXITCODE -"@ | Set-Content -LiteralPath $runner - - $output = & $script:pwsh -NoProfile -File $runner 2>&1 | Out-String - - $LASTEXITCODE | Should -Not -Be 0 - $output | Should -Match 'Migration activation failed' - Test-Path -LiteralPath (Join-Path $fixture.Docs '.git') -PathType Container | Should -BeTrue - Test-Path -LiteralPath (Join-Path $fixture.Workspace 'docs.git') | Should -BeFalse - Test-Path -LiteralPath (Join-Path $fixture.Workspace 'docs.simple-clone-backup') | Should -BeFalse - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() | Should -BeExactly $before - } - - It 'removes prepared backing when moving the simple clone fails' { - $before = (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() - $runner = Join-Path $fixture.Root 'invoke-failed-move.ps1' - $bootstrap = $script:bootstrap.Replace("'", "''") - $workspace = $fixture.Workspace.Replace("'", "''") - $docsRemote = $fixture.Remotes.docs.Replace("'", "''") - $memoryRemote = $fixture.Remotes.memory.Replace("'", "''") - @" -`$env:MSX_BOOTSTRAP_TEST_FAIL_DOCS_MOVE = '1' -`$projects = @( - @{ - Name = 'Fixture' - Path = '' - DocsUrl = '$docsRemote' - MemoryUrl = '$memoryRemote' - } -) -& '$bootstrap' -Root '$workspace' -Project `$projects -UserName 'Fixture User' -UserEmail 'fixture@example.invalid' -exit `$LASTEXITCODE -"@ | Set-Content -LiteralPath $runner - - $output = & $script:pwsh -NoProfile -File $runner 2>&1 | Out-String - - $LASTEXITCODE | Should -Not -Be 0 - $output | Should -Match 'Migration activation failed' - Test-Path -LiteralPath (Join-Path $fixture.Docs '.git') -PathType Container | Should -BeTrue - Test-Path -LiteralPath (Join-Path $fixture.Workspace 'docs.git') | Should -BeFalse - Test-Path -LiteralPath (Join-Path $fixture.Workspace 'docs.simple-clone-backup') | Should -BeFalse - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly $before - (Invoke-Git -WorkingDirectory $fixture.Docs -Arguments @('status', '--porcelain')) | - Should -BeNullOrEmpty - } - - It 'installs canonical topology from the seed block' -ForEach @( - @{ Name = 'agent template'; MarkdownPath = '../bootstrap/AGENTS.template.md' } - @{ Name = 'bootstrap README'; MarkdownPath = '../bootstrap/README.md' } - ) { - $workspace = Join-Path $fixture.Root "seed-$($Name.Replace(' ', '-'))" - $seedPath = Join-Path $PSScriptRoot $MarkdownPath - - $result = Invoke-BootstrapSeed -Fixture $fixture -MarkdownPath $seedPath -Workspace $workspace - - $result.ExitCode | Should -Be 0 -Because $result.Output - $docs = Join-Path $workspace 'docs' - $backing = Join-Path $workspace 'docs.git' - $memory = Join-Path $workspace 'memory' - Test-Path -LiteralPath (Join-Path $docs '.git') -PathType Leaf | Should -BeTrue - (Invoke-Git -Arguments @("--git-dir=$backing", 'rev-parse', '--is-bare-repository')).Trim() | - Should -BeExactly 'true' - (Invoke-Git -WorkingDirectory $docs -Arguments @('branch', '--show-current')).Trim() | Should -BeExactly 'main' - (Invoke-Git -WorkingDirectory $docs -Arguments @('status', '--porcelain')) | Should -BeNullOrEmpty - (Invoke-Git -WorkingDirectory $docs -Arguments @('rev-parse', 'HEAD')).Trim() | - Should -BeExactly (Invoke-Git -WorkingDirectory $fixture.Writers.docs -Arguments @('rev-parse', 'HEAD')).Trim() - Test-Path -LiteralPath (Join-Path $memory '.git') -PathType Container | - Should -BeTrue -Because $result.Output - (Invoke-Git -WorkingDirectory $docs -Arguments @('config', '--local', 'user.name')).Trim() | - Should -BeExactly 'Marius Storhaug' - (Invoke-BootstrapSeed -Fixture $fixture -MarkdownPath $seedPath -Workspace $workspace).ExitCode | - Should -Be 0 - } - - It 'refreshes a stale bare backing before the seed creates its canonical worktree' { - $workspace = Join-Path $fixture.Root 'seed-stale-backing' - New-Item -ItemType Directory -Path $workspace | Out-Null - $backing = Join-Path $workspace 'docs.git' - Invoke-Git -Arguments @('clone', '--bare', '--quiet', $fixture.Remotes.docs, $backing) | Out-Null - Add-TestCommit -Repository $fixture.Writers.docs -Name 'Advance before seed' - Invoke-Git -WorkingDirectory $fixture.Writers.docs -Arguments @('push', '--quiet') | Out-Null - $remoteHead = (Invoke-Git -WorkingDirectory $fixture.Writers.docs -Arguments @('rev-parse', 'HEAD')).Trim() - - $result = Invoke-BootstrapSeed -Fixture $fixture -MarkdownPath $script:agentTemplate -Workspace $workspace - - $result.ExitCode | Should -Be 0 -Because $result.Output - $docs = Join-Path $workspace 'docs' - (Invoke-Git -Arguments @("--git-dir=$backing", 'rev-parse', 'main')).Trim() | Should -BeExactly $remoteHead - (Invoke-Git -WorkingDirectory $docs -Arguments @('rev-parse', 'HEAD')).Trim() | Should -BeExactly $remoteHead } } From 0947337c2e711718007ce6a49f0feec2b54b8b83 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 10:37:30 +0200 Subject: [PATCH 07/23] Document optional organization defaults --- .../Ways-of-Working/Organization-Standard.md | 23 ++++++++++++++++++- .../Ways-of-Working/Repository-Standard.md | 8 ++++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/docs/Ways-of-Working/Organization-Standard.md b/src/docs/Ways-of-Working/Organization-Standard.md index cf1d7f6..a899b1f 100644 --- a/src/docs/Ways-of-Working/Organization-Standard.md +++ b/src/docs/Ways-of-Working/Organization-Standard.md @@ -31,7 +31,8 @@ Every initiative organization must define standards for these shared file famili | File family | Standard owns | | --- | --- | -| Community health files | Central code of conduct, contribution guide, support policy, security policy, and pull request template defaults. | +| Community health files | Central code of conduct, support policy, security policy, and pull request template defaults, plus contribution guidance where provided. | +| Issue intake | Central issue forms and issue-template configuration defaults, where the organization wants a shared intake model. | | Repository context | README defaults, documentation ownership, and repository metadata expectations. | | Review workflow | Pull request template, review routing, CODEOWNERS, namespace-qualified automation label sets, and change-type conventions. | | Supply chain | Dependency update configuration, security update behavior, and review expectations. | @@ -63,6 +64,26 @@ A repository MAY carry a local copy only when it needs a material, repository-specific exception. The local copy takes precedence, so the exception and its owner MUST be documented in the initiative guidance. +An organization MAY also provide optional defaults in the same repository: + +| File or directory | Purpose | +| --- | --- | +| `.github/CONTRIBUTING.md` | Provides organization-wide contribution guidance that repositories can inherit or use as the source for their local contribution guide. | +| `.github/ISSUE_TEMPLATE/` | Provides shared issue forms and template configuration for consistent issue intake. | +| `.github/copilot-instructions.md` | Provides organization-wide Copilot context that points to, and does not replace, the canonical standards. | + +These optional defaults are subscriptions, not additional repository baseline +files. A repository-local contribution guide remains required where the +[Repository Standard](Repository-Standard.md#required-files) calls for +repository-specific build, test, or contribution instructions. A repository MAY +provide local issue templates or agent instructions when it needs a documented +local variation. + +The special `.github` repository itself still follows the repository baseline: +its `README.md`, `AGENTS.md`, and client routes explain and govern that defaults +repository. Those repository-local context files are not distributed as +organization defaults. + ## Repository-local context is the enforceable surface Every repository still carries the context that cannot be inferred from an diff --git a/src/docs/Ways-of-Working/Repository-Standard.md b/src/docs/Ways-of-Working/Repository-Standard.md index 4ce70fa..a89840c 100644 --- a/src/docs/Ways-of-Working/Repository-Standard.md +++ b/src/docs/Ways-of-Working/Repository-Standard.md @@ -33,9 +33,11 @@ discoverability minimum defined below instead. | `.gitignore` | Ignores files that must never be committed, tailored to the repository's ecosystem: operating-system files, editor and developer-tooling files, language and test-harness artifacts, and all local build outputs and files created during build and test. | The organization provides `CODE_OF_CONDUCT.md`, `SECURITY.md`, `SUPPORT.md`, -and `.github/pull_request_template.md` as GitHub community defaults. Do not -copy them into a repository unless it needs a documented local exception; see -[Organization Standard](Organization-Standard.md#community-files-are-organization-defaults). +and `.github/pull_request_template.md` as GitHub community defaults. It MAY +also provide `.github/CONTRIBUTING.md`, `.github/ISSUE_TEMPLATE/`, and +`.github/copilot-instructions.md` as optional defaults. Do not copy any of +these organization defaults into a repository unless it needs a documented +local exception; see [Organization Standard](Organization-Standard.md#community-files-are-organization-defaults). Repository types may require additional files. For example, a PowerShell module may require `.github/PSModule.yml`, while a GitHub Action may require `action.yml`. From b1536ea360593f85ba5a06e1dcf19082992da789 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 10:40:59 +0200 Subject: [PATCH 08/23] Define the organization defaults repository surface --- .../repository-governance/design.md | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/docs/Capabilities/repository-governance/design.md b/src/docs/Capabilities/repository-governance/design.md index 8964dc2..7c0fa65 100644 --- a/src/docs/Capabilities/repository-governance/design.md +++ b/src/docs/Capabilities/repository-governance/design.md @@ -80,6 +80,48 @@ Bypass is granted on each ruleset to a **named administrative group in pull-request mode only** — never to individuals, and never as a blanket write exception ([FR16](spec.md#bypass)). +## Organization defaults repository + +Each organization carries one public repository named `.github`. It has three +distinct surfaces: community files that GitHub inherits into repositories, +content published on the organization's profile, and local context that governs +the defaults repository itself. Treating those surfaces as one distributable +file set would copy repository-specific configuration into places where it does +not belong. + +The [MSXOrg defaults repository](https://github.com/MSXOrg/.github) and the +[PSModule defaults repository](https://github.com/PSModule/.github) implement +the same structure: + +| Surface | Status | Behavior | +| --- | --- | --- | +| `.github/CODE_OF_CONDUCT.md` | Required | Inherited by a repository that has no local code of conduct. | +| `.github/SECURITY.md` | Required | Inherited by a repository that has no local security policy. | +| `.github/SUPPORT.md` | Required | Inherited by a repository that has no local support policy. | +| `.github/pull_request_template.md` | Required | Used when a repository has no local pull request template. | +| `.github/CONTRIBUTING.md` | Optional | Provides an organization-wide fallback where local contribution guidance is absent. | +| `.github/ISSUE_TEMPLATE/` | Optional | Provides the organization's issue forms and template configuration where a repository defines no local issue-template set. | +| `profile/README.md` | Optional | Publishes the public organization profile; it is not inherited by repositories. | +| `media/` | Optional | Holds assets used by the profile or community files; it is not inherited by repositories. | +| `README.md`, `AGENTS.md`, client routes, `.gitattributes`, and `.gitignore` | Required locally | Explain and govern the defaults repository; they are not organization defaults. | + +All inherited community files live under `.github/` in the defaults repository +so their scope is visible from their path. A local file in a target repository +takes precedence and therefore records a deliberate repository exception. If a +target defines any local issue-template set, it owns that complete set rather +than combining local and central forms. + +The defaults repository does not centralize repository ownership, dependency +updates, release configuration, license terms, or other repository-specific +configuration. Those files remain in each target repository because either +their values vary by repository or the platform does not inherit them. + +Client routes are also repository-specific. In particular, +`.github/copilot-instructions.md` in the defaults repository routes Copilot for +that repository only; it is not an organization-wide file default. +Organization-wide Copilot instructions are configured through the organization +settings and point to the same canonical standards rather than copying them. + ### The promotion-source check Branch protection can require a check; it cannot express "only from this branch". @@ -173,6 +215,8 @@ change](../../Ways-of-Working/Principles/AI-First-Development.md#decision-before | Which controls a type implies | Organization rulesets | | Required approvals per type | Organization rulesets | | Bypass group | Organization rulesets | +| Organization community defaults | Public organization `.github` repository | +| Organization-wide Copilot instructions | Organization Copilot settings | | Required-file set per type | [Repository Standard](../../Ways-of-Working/Repository-Standard.md#required-files) | | Comparison severities | Reconciliation configuration | | Reconciliation schedule | Reconciliation configuration | From 791f67189eaf56d9c7f2907160c8f67372068a9d Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 10:41:30 +0200 Subject: [PATCH 09/23] Align standards with central repository roles --- .../Ways-of-Working/Organization-Standard.md | 35 +++++++++++++------ .../Ways-of-Working/Repository-Standard.md | 15 +++++--- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/docs/Ways-of-Working/Organization-Standard.md b/src/docs/Ways-of-Working/Organization-Standard.md index a899b1f..c7007ba 100644 --- a/src/docs/Ways-of-Working/Organization-Standard.md +++ b/src/docs/Ways-of-Working/Organization-Standard.md @@ -33,11 +33,12 @@ Every initiative organization must define standards for these shared file famili | --- | --- | | Community health files | Central code of conduct, support policy, security policy, and pull request template defaults, plus contribution guidance where provided. | | Issue intake | Central issue forms and issue-template configuration defaults, where the organization wants a shared intake model. | +| Organization profile | The public organization introduction and any assets it uses. | | Repository context | README defaults, documentation ownership, and repository metadata expectations. | | Review workflow | Pull request template, review routing, CODEOWNERS, namespace-qualified automation label sets, and change-type conventions. | | Supply chain | Dependency update configuration, security update behavior, and review expectations. | | Linters and enforcement | Linter configuration derived from the written standards. | -| Agent context | Instructions, prompts, hooks, and any repository-local agent guidance. | +| Agent context | Organization settings plus repository-local instructions, prompts, hooks, and agent guidance. | | Release automation | Release notes, changelog categorization, and release workflow defaults where applicable. | These standards must be written down before broad alignment work starts. File alignment without a written standard only spreads local preference faster. @@ -70,29 +71,36 @@ An organization MAY also provide optional defaults in the same repository: | --- | --- | | `.github/CONTRIBUTING.md` | Provides organization-wide contribution guidance that repositories can inherit or use as the source for their local contribution guide. | | `.github/ISSUE_TEMPLATE/` | Provides shared issue forms and template configuration for consistent issue intake. | -| `.github/copilot-instructions.md` | Provides organization-wide Copilot context that points to, and does not replace, the canonical standards. | These optional defaults are subscriptions, not additional repository baseline files. A repository-local contribution guide remains required where the [Repository Standard](Repository-Standard.md#required-files) calls for repository-specific build, test, or contribution instructions. A repository MAY -provide local issue templates or agent instructions when it needs a documented -local variation. +provide local issue templates when it needs a documented local variation. -The special `.github` repository itself still follows the repository baseline: -its `README.md`, `AGENTS.md`, and client routes explain and govern that defaults -repository. Those repository-local context files are not distributed as -organization defaults. +The same repository MAY publish `profile/README.md` as the public organization +profile and MAY keep its supporting assets under `media/`. Neither surface is +inherited by repositories. + +The special `.github` repository has a purpose-specific local baseline: +`README.md`, `AGENTS.md`, its client routes, `.gitattributes`, and `.gitignore`. +Those files explain and govern the defaults repository and are not distributed +as organization defaults. Repository ownership, dependency updates, release +configuration, and license terms remain repository-specific and are added only +when the defaults repository itself needs them. The +[Repository Governance design](../Capabilities/repository-governance/design.md#organization-defaults-repository) +owns the complete structure and distribution behavior. ## Repository-local context is the enforceable surface -Every repository still carries the context that cannot be inferred from an -organization default: its `README.md`, `.github/CONTRIBUTING.md`, and +Every ordinary repository still carries the context that cannot be inferred +from an organization default: its `README.md`, `.github/CONTRIBUTING.md`, and `AGENTS.md` with its client routes. The contribution guide tells humans and agents how the organization defaults apply and where the central pull request template lives. Automation configuration, ownership, and repository-specific legal terms also remain repository-local where the -[Repository Standard](Repository-Standard.md) requires them. +[Repository Standard](Repository-Standard.md) requires them. The special +`.github` repository uses the purpose-specific baseline above. ## Managed files @@ -156,6 +164,11 @@ Agent files are allowed when they point to, summarize, or operationalize the cen The repository-level entry point is `AGENTS.md`, as defined by [Agentic Development](../Capabilities/agentic-development/design.md#client-behavior). Agent runtimes do not agree on a filename, so a repository also carries a route file for each client that reads a different one. A route holds a pointer to the router and, at most, genuinely runtime-specific configuration — never a duplicated standard or workflow. The same limit applies to any organization-level instruction setting an agent vendor offers: use it for organization-wide preferences, never as a second copy of a standard. +The `.github/copilot-instructions.md` route in the special `.github` +repository applies to that repository only. Organization-wide Copilot +instructions are configured in the organization settings and point to the +canonical standards. + ## Where this connects - [Repository Standard](Repository-Standard.md) — the repository-level contract every repository must satisfy. diff --git a/src/docs/Ways-of-Working/Repository-Standard.md b/src/docs/Ways-of-Working/Repository-Standard.md index a89840c..48c75aa 100644 --- a/src/docs/Ways-of-Working/Repository-Standard.md +++ b/src/docs/Ways-of-Working/Repository-Standard.md @@ -34,10 +34,17 @@ discoverability minimum defined below instead. The organization provides `CODE_OF_CONDUCT.md`, `SECURITY.md`, `SUPPORT.md`, and `.github/pull_request_template.md` as GitHub community defaults. It MAY -also provide `.github/CONTRIBUTING.md`, `.github/ISSUE_TEMPLATE/`, and -`.github/copilot-instructions.md` as optional defaults. Do not copy any of -these organization defaults into a repository unless it needs a documented -local exception; see [Organization Standard](Organization-Standard.md#community-files-are-organization-defaults). +also provide `.github/CONTRIBUTING.md` and `.github/ISSUE_TEMPLATE/` as +optional defaults. Do not copy any of these organization defaults into a +repository unless it needs a documented local exception; see +[Organization Standard](Organization-Standard.md#community-files-are-organization-defaults). + +The special organization `.github` repository uses the purpose-specific file +set defined by the +[Repository Governance design](../Capabilities/repository-governance/design.md#organization-defaults-repository) +instead of carrying repository-specific baseline files that have no function +there. Its own README, agent routes, text handling, and ignore rules remain +local; only supported community defaults are inherited by other repositories. Repository types may require additional files. For example, a PowerShell module may require `.github/PSModule.yml`, while a GitHub Action may require `action.yml`. From 85e6da6a3414bc85acc95aee903ff31160e2495a Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 10:42:44 +0200 Subject: [PATCH 10/23] Use the repository language standard --- src/docs/Ways-of-Working/Organization-Standard.md | 2 +- src/docs/Ways-of-Working/Repository-Standard.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/docs/Ways-of-Working/Organization-Standard.md b/src/docs/Ways-of-Working/Organization-Standard.md index c7007ba..181a4a1 100644 --- a/src/docs/Ways-of-Working/Organization-Standard.md +++ b/src/docs/Ways-of-Working/Organization-Standard.md @@ -56,7 +56,7 @@ the special `.github` repository: | File | Purpose | | --- | --- | -| `.github/CODE_OF_CONDUCT.md` | Defines expected community behaviour. | +| `.github/CODE_OF_CONDUCT.md` | Defines expected community behavior. | | `.github/SECURITY.md` | Defines supported versions and private vulnerability reporting. | | `.github/SUPPORT.md` | Defines where users ask for help. | | `.github/pull_request_template.md` | Scaffolds pull requests in the organization's required format. | diff --git a/src/docs/Ways-of-Working/Repository-Standard.md b/src/docs/Ways-of-Working/Repository-Standard.md index 48c75aa..3053111 100644 --- a/src/docs/Ways-of-Working/Repository-Standard.md +++ b/src/docs/Ways-of-Working/Repository-Standard.md @@ -1,6 +1,6 @@ --- title: Repository Standard -description: The baseline files and behaviours every repository must expose so it is understandable, secure, and maintainable. +description: The baseline files and behaviors every repository must expose so it is understandable, secure, and maintainable. --- # Repository Standard From 3db29b1344458128172841f9dfbeb24dcefee35e Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 11:52:14 +0200 Subject: [PATCH 11/23] Simplify the global agent template --- bootstrap/AGENTS.template.md | 169 ++--------------------------------- bootstrap/README.md | 2 +- 2 files changed, 6 insertions(+), 165 deletions(-) diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md index 1c5e65f..c8e7099 100644 --- a/bootstrap/AGENTS.template.md +++ b/bootstrap/AGENTS.template.md @@ -1,167 +1,8 @@ -# MSX workspace +# AGENTS -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. +Read the newest version of the docs in this order: -## Main directive +1. [`MSXOrg/docs`](https://github.com/MSXOrg/docs) — organization standards. + Store a local clone at `~/.msxorg/docs`. -Everything is a work in progress and can be updated and improved. Fix a small problem when it is directly in scope; register a larger or unrelated problem as an issue in the repository that owns it. - -## First — bootstrap the workspace - -The workspace is a git-isolated clone of the organization documentation repository under `~/.msxorg` by default. Set it up before reading context. Use a separate organization-named root, such as `~/.psmodule` for PSModule. The existing context repository must be clean, on its default branch, and exactly synchronized with the remote: - -```powershell -$workspaceRoot = if ($env:MSX_WORKSPACE_ROOT) { $env:MSX_WORKSPACE_ROOT } else { Join-Path $HOME '.msxorg' } -$docsUrl = if ($env:MSX_DOCS_URL) { $env:MSX_DOCS_URL } else { 'https://github.com/MSXOrg/docs.git' } -$docs = Join-Path $workspaceRoot 'docs' -$docsBacking = "$docs.git" -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'))) { - if (-not (Test-Path $docsBacking)) { - New-Item -ItemType Directory -Force -Path (Split-Path -Parent $docs) | Out-Null - git clone --bare $docsUrl $docsBacking - if ($LASTEXITCODE -ne 0) { - throw "Bare clone of MSXOrg/docs failed (exit $LASTEXITCODE). Check network access and credentials." - } - } - if ((git --git-dir=$docsBacking rev-parse --is-bare-repository) -ne 'true') { - throw "$docsBacking exists but is not a bare repository." - } - if ((git --git-dir=$docsBacking remote get-url origin) -ne $docsUrl) { - throw "$docsBacking origin does not match canonical $docsUrl." - } - $refspec = '+refs/heads/*:refs/remotes/origin/*' - if ($refspec -notin @(git --git-dir=$docsBacking config --get-all remote.origin.fetch)) { - git --git-dir=$docsBacking config --add remote.origin.fetch $refspec - if ($LASTEXITCODE -ne 0) { throw "Could not configure $docsBacking." } - } - git --git-dir=$docsBacking fetch origin --prune --quiet - if ($LASTEXITCODE -ne 0) { throw "Could not refresh $docsBacking. Do not use stale context." } - git --git-dir=$docsBacking remote set-head origin --auto | Out-Null - if ($LASTEXITCODE -ne 0) { throw "Could not detect the MSXOrg/docs default branch." } - $defaultRef = (git --git-dir=$docsBacking symbolic-ref --short refs/remotes/origin/HEAD | Out-String).Trim() - if ($LASTEXITCODE -ne 0) { throw "Could not resolve origin/HEAD in $docsBacking." } - $defaultBranch = $defaultRef -replace '^origin/', '' - $remoteHead = (git --git-dir=$docsBacking rev-parse $defaultRef | Out-String).Trim() - if ($LASTEXITCODE -ne 0) { throw "Could not resolve $defaultRef in $docsBacking." } - $localRef = "refs/heads/$defaultBranch" - $localHead = (git --git-dir=$docsBacking rev-parse --verify $localRef 2>$null | Out-String).Trim() - if ($LASTEXITCODE -eq 128) { - git --git-dir=$docsBacking update-ref $localRef $remoteHead - } elseif ($LASTEXITCODE -ne 0) { - throw "Could not inspect $localRef in $docsBacking." - } elseif ($localHead -ne $remoteHead) { - git --git-dir=$docsBacking merge-base --is-ancestor $localHead $remoteHead - if ($LASTEXITCODE -ne 0) { throw "$localRef is ahead or diverged in $docsBacking." } - if ("branch $localRef" -in @(git --git-dir=$docsBacking worktree list --porcelain)) { - throw "$localRef is checked out elsewhere. Update that worktree first." - } - git --git-dir=$docsBacking update-ref $localRef $remoteHead $localHead - } - if ($LASTEXITCODE -ne 0 -or (git --git-dir=$docsBacking rev-parse $localRef) -ne $remoteHead) { - throw "$localRef is not exactly synchronized with $defaultRef." - } - git --git-dir=$docsBacking worktree add $docs $defaultBranch - if ($LASTEXITCODE -ne 0) { - throw "Could not create the canonical MSXOrg/docs worktree at $docs." - } -} else { - if ((git -C $docs remote get-url origin) -ne $docsUrl) { - throw "$docs origin does not match canonical $docsUrl." - } - $refspec = '+refs/heads/*:refs/remotes/origin/*' - if ($refspec -notin @(git -C $docs config --get-all remote.origin.fetch)) { - git -C $docs config --add remote.origin.fetch $refspec - if ($LASTEXITCODE -ne 0) { - throw "Could not configure remote tracking branches for MSXOrg/docs (exit $LASTEXITCODE)." - } - } - git -C $docs fetch origin --prune --quiet - if ($LASTEXITCODE -ne 0) { - throw "git fetch of MSXOrg/docs failed (exit $LASTEXITCODE). Do not use stale context." - } - git -C $docs remote set-head origin --auto | Out-Null - if ($LASTEXITCODE -ne 0) { throw "Could not detect the MSXOrg/docs default branch." } - $defaultRef = (git -C $docs symbolic-ref --short refs/remotes/origin/HEAD | Out-String).Trim() - if ($LASTEXITCODE -ne 0) { throw "Could not resolve origin/HEAD in $docs." } - $defaultBranch = $defaultRef -replace '^origin/', '' - $branch = (git -C $docs branch --show-current | Out-String).Trim() - if ($branch -ne $defaultBranch) { - throw "$docs is on '$branch', not '$defaultBranch'. Switch branches before using this context." - } - if (@(git -C $docs status --porcelain).Count -gt 0) { - throw "$docs has uncommitted changes. Resolve them before using this context." - } - git -C $docs merge --ff-only --quiet $defaultRef - if ($LASTEXITCODE -ne 0) { - throw "MSXOrg/docs cannot fast-forward to $defaultRef. Do not use stale context." - } - if ((git -C $docs rev-parse HEAD) -ne (git -C $docs rev-parse $defaultRef)) { - throw "$docs is not exactly synchronized with $defaultRef. Reconcile local commits before using this context." - } -} -$projects = @( - @{ - Name = 'MSXOrg' - Path = '' - DocsUrl = $docsUrl - } - # Add project-specific entries when this template is adopted there: - # @{ - # Name = 'PSModule' - # Path = '' - # DocsUrl = 'https://github.com/PSModule/docs.git' - # } -) -& (Join-Path $docs 'bootstrap/Initialize-MsxWorkspace.ps1') -Root $workspaceRoot -Project $projects -if ($LASTEXITCODE -ne 0) { - throw "Context synchronization failed. Do not read context until every project is current." -} -``` - -Keep the MSXOrg entry and add only the additional project coordinates required by repositories that inherit this template. Every project reuses the same synchronization and validation implementation. - -This produces: - -- `~/.msxorg/docs.git` — bare backing repository for central docs. -- `~/.msxorg/docs` — clean, readable main worktree containing ways of working, standards, and workflow guidance. - -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 - -1. Segment the work by host, organization, repository, path, and task, so the right project context is selected before any of it is loaded. -2. Start at `~/.msxorg/docs/src/docs/index.md`. -3. Follow the Ways of Working index to `Workflow.md`. -4. Infer the current stage from the task and its artifacts, then read the linked stage procedure. - -In a repository, its root `AGENTS.md` names the host and organization and lists the order to read in. This file carries the bootstrap and the segmentation step; the repository file carries the route. Neither restates the other. - -Clear task language may shortcut the index trail: `Review this PR ` enters Review, `Make this issue ` enters Define, and `Implement ` enters Implement. The linked documentation owns each procedure; this file does not define a separate agent or skill. - -## Interactions - -Some phrases operate on the session rather than on the work, and each one resolves to a procedure defined in the canonical Ways of Working: - -| Phrase | Means | -| --- | --- | -| `wrap up` | The session is ending — scan for untracked work and land each item in its proper artifact. | -| `park` | Move a tangent into an issue in the repository that owns it, then resume the original task. | -| `triage` | Classify and route an item without starting implementation. | -| `handoff` | Bring the artifacts to a state another participant can resume from. | - -Read `Ways-of-Working/Session-Interactions.md` in the canonical docs for what each one does. This table is a route, not a definition. - -## Work in the selected repository - -1. Read its `README.md` to understand the repository and its build. -2. Read its `.github/CONTRIBUTING.md` for the contribution and review contract. -3. Use a dedicated worktree and the branch naming defined by the canonical Ways of Working. -4. Make small, descriptive micro-commits and push every commit so remote state, CI, and the draft pull request stay current. - -## Two write rules - -- **Docs change through topic worktrees and pull requests.** Create a topic worktree from `~/.msxorg/docs.git`; never branch or work inside the canonical `~/.msxorg/docs` main worktree. +Do not trust your memory. diff --git a/bootstrap/README.md b/bootstrap/README.md index e04b42f..863de29 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -5,7 +5,7 @@ The single starting point for agents: a git-isolated local clone of the MSXOrg d ## Contents - `Initialize-MsxWorkspace.ps1` — idempotent setup. Clones `MSXOrg/docs` under `~/.msxorg`, requires the existing clone to exactly match its remote default branch, 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. Install it once per machine (below). +- `AGENTS.template.md` — the user-global entry instruction. It points agents to the local MSXOrg docs clone. Install it once per machine (below). ## The model From 806f7a741a9f1281130352c1b26885807724df0f Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 11:58:32 +0200 Subject: [PATCH 12/23] Align agent context routing docs --- bootstrap/AGENTS.template.md | 42 +- bootstrap/Initialize-MsxWorkspace.ps1 | 518 ------------------ bootstrap/README.md | 184 +------ .../agentic-development/conformance.md | 2 +- .../agentic-development/design.md | 73 +-- .../Capabilities/agentic-development/index.md | 4 +- .../plugin-distribution.md | 2 +- .../runtime-integration.md | 27 +- .../Capabilities/agentic-development/spec.md | 16 +- src/docs/Ways-of-Working/Git-Worktrees.md | 8 +- src/docs/Ways-of-Working/index.md | 4 +- tests/Initialize-MsxWorkspace.Tests.ps1 | 61 --- 12 files changed, 135 insertions(+), 806 deletions(-) delete mode 100644 bootstrap/Initialize-MsxWorkspace.ps1 delete mode 100644 tests/Initialize-MsxWorkspace.Tests.ps1 diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md index c8e7099..28647b4 100644 --- a/bootstrap/AGENTS.template.md +++ b/bootstrap/AGENTS.template.md @@ -1,8 +1,42 @@ # AGENTS -Read the newest version of the docs in this order: +This file is installed as user-level agent instructions. It is the first +context route: it identifies the current organization's canonical `docs` +repository, makes that repository available locally, and directs the agent to +the repository's own `AGENTS.md`. -1. [`MSXOrg/docs`](https://github.com/MSXOrg/docs) — organization standards. - Store a local clone at `~/.msxorg/docs`. +Ensure `~/.msxorg/docs` is a clean clone of +[`MSXOrg/docs`](https://github.com/MSXOrg/docs) before reading context: -Do not trust your memory. +```powershell +git clone https://github.com/MSXOrg/docs.git ~/.msxorg/docs +``` + +If the clone already exists, use Git to fetch and fast-forward it to its +default branch. If the path is not a Git clone, or it has local changes or +local commits, stop and resolve that state rather than reading stale context. + +The repository's `AGENTS.md` is the context router. It reads local guidance +first — `README.md`, `.github/CONTRIBUTING.md`, and repository documentation — +then routes outward to the current organization guidance in +`~/.msxorg/docs/src/docs/index.md`. Client-specific files point to that router: + +```markdown +# Claude Code +@../AGENTS.md +``` + +```markdown +Follow the instructions in [AGENTS.md](../AGENTS.md). +``` + +The first example is `.claude/CLAUDE.md`; the second is +`.github/copilot-instructions.md`. Other clients use the equivalent pointer +file they recognize. These files stay shallow so `AGENTS.md` remains the one +context route. + +For faster discovery, install the shared `msxorg` Agent Plugin marketplace +from `~/.msxorg/docs/.github/plugin/marketplace.json`. Its skills are also +shallow pointers: each skill routes a coding, documentation, or +ways-of-working intent to one canonical page in `MSXOrg/docs`; skills do not +copy the guidance. diff --git a/bootstrap/Initialize-MsxWorkspace.ps1 b/bootstrap/Initialize-MsxWorkspace.ps1 deleted file mode 100644 index 9516bc8..0000000 --- a/bootstrap/Initialize-MsxWorkspace.ps1 +++ /dev/null @@ -1,518 +0,0 @@ -#!/usr/bin/env pwsh -#Requires -Version 7.0 - -<# -.SYNOPSIS - Clone or update canonical project context repositories in a git-isolated workspace under $HOME. - -.DESCRIPTION - The single starting point for every agent. It ensures the central - documentation repositories for each configured project exist - locally under one dedicated workspace, so an agent reads current canonical - context regardless of which repository it is working in. - - The workspace is deliberately kept separate from the repositories an agent - works in: - - - Each docs repository uses a bare backing repository plus a canonical clean - default-branch worktree. Topic branches use separate worktrees. - - Every checkout gets repository-local git config only. Nothing here modifies - global git config or the working product repository. - - The script synchronizes context but never writes or pushes repository content. - - The script is idempotent: it clones what is missing and synchronizes every - existing context repository to the exact remote default-branch head. It stops - before context is read when a repository is dirty, on another branch, locally - ahead, diverged, or unavailable. - -.EXAMPLE - ./Initialize-MsxWorkspace.ps1 - Clones missing repositories and exactly synchronizes existing ones under ~/.msxorg. - -.EXAMPLE - ./Initialize-MsxWorkspace.ps1 -Root /work/.msxorg -Verbose - Uses a custom workspace root and logs each step. - -.EXAMPLE - $projects = @( - @{ - Name = 'PSModule' - Path = '' - DocsUrl = 'https://github.com/PSModule/docs.git' - } - ) - ./Initialize-MsxWorkspace.ps1 -Project $projects - Installs a project's docs under a project-specific workspace path. - -.OUTPUTS - [pscustomobject] with Repository, Path, BackingPath, and Changes for each - workspace repository. -#> -[CmdletBinding(SupportsShouldProcess)] -param( - # The organization workspace root under which documentation is placed. - [Parameter()] - [ValidateNotNullOrEmpty()] - [string] $Root = (Join-Path $HOME '.msxorg'), - - # 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', - - # Projects whose canonical documentation repositories must be synchronized. - [Parameter()] - [ValidateNotNullOrEmpty()] - [hashtable[]] $Project = @( - @{ - Name = 'MSXOrg' - Path = '' - DocsUrl = 'https://github.com/MSXOrg/docs.git' - } - ) -) - -Set-StrictMode -Version Latest -$ErrorActionPreference = 'Stop' - -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 set your own repository-local author identity." -} - -function Assert-ContextOrigin { - param( - [Parameter(Mandatory)] - [string] $GitPath, - - [Parameter(Mandatory)] - [string] $RepositoryUrl, - - [Parameter()] - [switch] $Bare - ) - - [string[]] $gitRoot = if ($Bare) { @("--git-dir=$GitPath") } else { @('-C', $GitPath) } - $originUrl = (& git @gitRoot remote get-url origin | Out-String).Trim() - if ($LASTEXITCODE -ne 0) { - throw "Cannot resolve origin for '$GitPath'. Configure it as '$RepositoryUrl'." - } - if ($originUrl -ne $RepositoryUrl) { - throw "Origin for '$GitPath' is '$originUrl', not canonical '$RepositoryUrl'. Repair it before using this context." - } -} - -function Sync-ContextRemote { - [CmdletBinding(SupportsShouldProcess)] - param( - [Parameter(Mandatory)] - [string] $GitPath, - - [Parameter(Mandatory)] - [string] $RepositoryUrl, - - [Parameter()] - [switch] $Bare - ) - - if (-not $PSCmdlet.ShouldProcess($GitPath, 'Fetch canonical remote state')) { - return - } - - [string[]] $gitRoot = if ($Bare) { @("--git-dir=$GitPath") } else { @('-C', $GitPath) } - Assert-ContextOrigin -GitPath $GitPath -RepositoryUrl $RepositoryUrl -Bare:$Bare - $allBranchesRefspec = '+refs/heads/*:refs/remotes/origin/*' - $fetchRefspecs = @(& git @gitRoot config --get-all remote.origin.fetch) - if ($LASTEXITCODE -notin @(0, 1)) { - throw "git config remote.origin.fetch failed for '$GitPath' (exit $LASTEXITCODE)." - } - if ($allBranchesRefspec -notin $fetchRefspecs) { - & git @gitRoot config --add remote.origin.fetch $allBranchesRefspec - if ($LASTEXITCODE -ne 0) { - throw "Could not configure remote tracking branches for '$GitPath' (exit $LASTEXITCODE)." - } - } - - & git @gitRoot fetch origin --prune --quiet - if ($LASTEXITCODE -ne 0) { - throw "git fetch failed for '$GitPath' (exit $LASTEXITCODE). Check access to $RepositoryUrl." - } - & git @gitRoot remote set-head origin --auto | Out-Null - if ($LASTEXITCODE -ne 0) { - throw "Cannot detect the remote default branch for '$GitPath'. Check origin before using this context." - } - - $defaultRef = (& git @gitRoot symbolic-ref --quiet --short refs/remotes/origin/HEAD | Out-String).Trim() - if ($LASTEXITCODE -ne 0) { - throw "Cannot resolve the remote default branch for '$GitPath'. Repair origin/HEAD before using this context." - } - $remoteHead = (& git @gitRoot rev-parse $defaultRef | Out-String).Trim() - if ($LASTEXITCODE -ne 0 -or -not $remoteHead) { - throw "Cannot resolve remote head '$defaultRef' for '$GitPath'." - } - return [pscustomobject]@{ - DefaultRef = $defaultRef - DefaultBranch = $defaultRef -replace '^origin/', '' - RemoteHead = $remoteHead - } -} - -function Sync-ContextCheckout { - [CmdletBinding(SupportsShouldProcess)] - param( - [Parameter(Mandatory)] - [string] $Path, - - [Parameter(Mandatory)] - [string] $RepositoryUrl - ) - - $remote = Sync-ContextRemote -GitPath $Path -RepositoryUrl $RepositoryUrl -Confirm:$false - if (-not $remote -or -not $PSCmdlet.ShouldProcess($Path, "Synchronize $($remote.DefaultBranch)")) { - return $remote - } - - $currentBranch = (git -C $Path branch --show-current | Out-String).Trim() - if ($LASTEXITCODE -ne 0) { - throw "git branch --show-current failed for '$Path' (exit $LASTEXITCODE)." - } - if ($currentBranch -ne $remote.DefaultBranch) { - throw "'$Path' is on '$currentBranch', not the default branch '$($remote.DefaultBranch)'. Switch branches before using this context." - } - - $status = @(git -C $Path status --porcelain) - if ($LASTEXITCODE -ne 0) { - throw "git status failed for '$Path' (exit $LASTEXITCODE)." - } - if ($status.Count -gt 0) { - throw "'$Path' has uncommitted changes. Commit, push, or remove them before using this context." - } - - git -C $Path merge --ff-only --quiet $remote.DefaultRef - if ($LASTEXITCODE -ne 0) { - throw "Could not fast-forward '$Path' to '$($remote.DefaultRef)'. Resolve its diverged history before using this context." - } - $localHead = (git -C $Path rev-parse HEAD | Out-String).Trim() - if ($LASTEXITCODE -ne 0) { - throw "git rev-parse HEAD failed for '$Path' (exit $LASTEXITCODE)." - } - if ($localHead -ne $remote.RemoteHead) { - throw "'$Path' is not exactly synchronized with '$($remote.DefaultRef)'. Push or reconcile local commits before using this context." - } - return $remote -} - -function Sync-BareDefaultBranch { - [CmdletBinding(SupportsShouldProcess)] - param( - [Parameter(Mandatory)] - [string] $BackingPath, - - [Parameter(Mandatory)] - [pscustomobject] $Remote - ) - - $localRef = "refs/heads/$($Remote.DefaultBranch)" - $localHead = (git --git-dir=$BackingPath rev-parse --verify $localRef 2>$null | Out-String).Trim() - if ($LASTEXITCODE -eq 128) { - if ($PSCmdlet.ShouldProcess($localRef, "Create at $($Remote.RemoteHead)")) { - git --git-dir=$BackingPath update-ref $localRef $Remote.RemoteHead - if ($LASTEXITCODE -ne 0) { - throw "Could not create bare docs branch '$localRef' in '$BackingPath'." - } - } - return - } - if ($LASTEXITCODE -ne 0) { - throw "Could not inspect bare docs branch '$localRef' in '$BackingPath'." - } - if ($localHead -eq $Remote.RemoteHead) { - return - } - - git --git-dir=$BackingPath merge-base --is-ancestor $localHead $Remote.RemoteHead - if ($LASTEXITCODE -ne 0) { - throw "Bare docs branch '$localRef' is ahead or diverged. Reconcile '$BackingPath' before creating its canonical worktree." - } - $worktreeState = @(git --git-dir=$BackingPath worktree list --porcelain) - if ($LASTEXITCODE -ne 0) { - throw "Could not inspect worktrees for '$BackingPath'." - } - if ("branch $localRef" -in $worktreeState) { - throw "Bare docs branch '$localRef' is checked out in another worktree. Update that worktree before creating the canonical one." - } - if ($PSCmdlet.ShouldProcess($localRef, "Fast-forward to $($Remote.RemoteHead)")) { - git --git-dir=$BackingPath update-ref $localRef $Remote.RemoteHead $localHead - if ($LASTEXITCODE -ne 0) { - throw "Could not fast-forward bare docs branch '$localRef' in '$BackingPath'." - } - } -} - -function Set-ContextIdentity { - [CmdletBinding(SupportsShouldProcess)] - param( - [Parameter(Mandatory)] - [string] $Path, - - [Parameter(Mandatory)] - [string] $Name, - - [Parameter(Mandatory)] - [string] $Email - ) - - if (-not $PSCmdlet.ShouldProcess($Path, 'Set repository-local git identity')) { - return - } - git -C $Path config user.name $Name - if ($LASTEXITCODE -ne 0) { throw "git config user.name failed for '$Path' (exit $LASTEXITCODE)." } - git -C $Path config user.email $Email - if ($LASTEXITCODE -ne 0) { throw "git config user.email failed for '$Path' (exit $LASTEXITCODE)." } -} - -$projectNames = [Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase) -$repositories = foreach ($projectDefinition in $Project) { - foreach ($key in @('Name', 'Path', 'DocsUrl')) { - if (-not $projectDefinition.ContainsKey($key) -or $null -eq $projectDefinition[$key]) { - throw "Project definitions require Name, Path, and DocsUrl. Missing '$key'." - } - } - - $projectName = [string] $projectDefinition.Name - $projectPath = ([string] $projectDefinition.Path).Trim() - if (-not $projectName.Trim()) { - throw 'Project Name must not be empty.' - } - $projectName = $projectName.Trim() - if (-not $projectNames.Add($projectName)) { - throw "Project definitions require unique names. Duplicate: '$projectName'." - } - $pathSegments = @($projectPath -split '[\\/]' | Where-Object { $_ -and $_ -ne '.' }) - if ([IO.Path]::IsPathRooted($projectPath) -or '..' -in $pathSegments) { - throw "Project Path '$projectPath' must be a safe path relative to the workspace root." - } - $projectPath = $pathSegments -join [IO.Path]::DirectorySeparatorChar - - $docsPath = if ($projectPath) { Join-Path $projectPath 'docs' } else { 'docs' } - [pscustomobject]@{ - Name = "$projectName/docs" - Project = $projectName - ProjectPath = $projectPath - Kind = 'docs' - RelativePath = $docsPath - Url = [string] $projectDefinition.DocsUrl - Changes = 'pull requests' - } -} - -$occupiedPaths = foreach ($repository in $repositories) { - [pscustomobject]@{ - Project = $repository.Project - Repository = $repository.Name - Path = $repository.RelativePath - } - if ($repository.Kind -eq 'docs') { - if ($repository.ProjectPath) { - [pscustomobject]@{ - Project = $repository.Project - Repository = "$($repository.Project) root" - Path = $repository.ProjectPath - } - } - [pscustomobject]@{ - Project = $repository.Project - Repository = "$($repository.Name) backing" - Path = "$($repository.RelativePath).git" - } - [pscustomobject]@{ - Project = $repository.Project - Repository = "$($repository.Name) migration backup" - Path = "$($repository.RelativePath).simple-clone-backup" - } - } -} -for ($left = 0; $left -lt $occupiedPaths.Count; $left++) { - $leftPath = ($occupiedPaths[$left].Path -replace '\\', '/').Trim('/').ToLowerInvariant() - for ($right = $left + 1; $right -lt $occupiedPaths.Count; $right++) { - if ($occupiedPaths[$left].Project -eq $occupiedPaths[$right].Project) { - continue - } - $rightPath = ($occupiedPaths[$right].Path -replace '\\', '/').Trim('/').ToLowerInvariant() - $collision = ( - $leftPath -eq $rightPath -or - $leftPath.StartsWith("$rightPath/", [StringComparison]::Ordinal) -or - $rightPath.StartsWith("$leftPath/", [StringComparison]::Ordinal) - ) - if ($collision) { - throw "Project workspace paths overlap: '$($occupiedPaths[$left].Path)' and '$($occupiedPaths[$right].Path)'." - } - } -} - -foreach ($repository in $repositories) { - $contextPath = Join-Path $Root $repository.RelativePath - $gitEntry = Join-Path $contextPath '.git' - if ($repository.Kind -eq 'docs') { - if (Test-Path $gitEntry -PathType Container) { - Assert-ContextOrigin -GitPath $contextPath -RepositoryUrl $repository.Url - } elseif (Test-Path $gitEntry -PathType Leaf) { - $commonDir = (git -C $contextPath rev-parse --path-format=absolute --git-common-dir | Out-String).Trim() - if ($LASTEXITCODE -ne 0) { - throw "Cannot resolve docs backing repository for '$contextPath'." - } - Assert-ContextOrigin -GitPath $commonDir -RepositoryUrl $repository.Url -Bare - } elseif (Test-Path "$contextPath.git") { - Assert-ContextOrigin -GitPath "$contextPath.git" -RepositoryUrl $repository.Url -Bare - } - } -} - -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.RelativePath - $expectedBackingPath = "$path.git" - $backingPath = $null - $gitEntry = Join-Path $path '.git' - if (Test-Path $gitEntry -PathType Container) { - # Safe simple-clone migration: synchronize first, preserve all refs in a - # new bare backing repository, and retain the old clone as a backup. - $remote = Sync-ContextCheckout -Path $path -RepositoryUrl $repo.Url -Confirm:$false - if (Test-Path $expectedBackingPath) { - throw "Cannot migrate '$path': backing path '$expectedBackingPath' already exists." - } - $backupPath = "$path.simple-clone-backup" - if (Test-Path $backupPath) { - throw "Cannot migrate '$path': backup path '$backupPath' already exists. Reconcile it first." - } - if ($PSCmdlet.ShouldProcess($path, "Migrate simple clone to '$expectedBackingPath'")) { - $sourceRefs = @(git -C $path for-each-ref '--format=%(refname) %(objectname)' refs/heads refs/tags) - if ($LASTEXITCODE -ne 0) { - throw "Could not inventory branches and tags in '$path' before migration." - } - try { - git clone --bare --quiet $path $expectedBackingPath - if ($LASTEXITCODE -ne 0) { - throw "Could not create bare backing repository '$expectedBackingPath' (exit $LASTEXITCODE)." - } - git --git-dir=$expectedBackingPath remote set-url origin $repo.Url - if ($LASTEXITCODE -ne 0) { - throw "Could not set origin on '$expectedBackingPath' (exit $LASTEXITCODE)." - } - Sync-ContextRemote -GitPath $expectedBackingPath -RepositoryUrl $repo.Url -Bare -Confirm:$false | Out-Null - $backingRefs = @(git --git-dir=$expectedBackingPath for-each-ref '--format=%(refname) %(objectname)' refs/heads refs/tags) - if ($LASTEXITCODE -ne 0 -or (Compare-Object $sourceRefs $backingRefs)) { - throw "Bare backing repository '$expectedBackingPath' did not preserve every local branch and tag." - } - } catch { - if (Test-Path $expectedBackingPath) { - Remove-Item -LiteralPath $expectedBackingPath -Recurse -Force - } - throw "Migration preparation failed for '$path'; the original clone is unchanged. $($_.Exception.Message)" - } - - $moved = $false - try { - if ($env:MSX_BOOTSTRAP_TEST_FAIL_DOCS_MOVE -eq '1') { - throw 'Injected migration move failure.' - } - Move-Item -LiteralPath $path -Destination $backupPath -ErrorAction Stop - $moved = $true - if ($env:MSX_BOOTSTRAP_TEST_FAIL_AFTER_DOCS_MOVE -eq '1') { - throw 'Injected post-move migration failure.' - } - git --git-dir=$expectedBackingPath worktree add --quiet $path $remote.DefaultBranch - if ($LASTEXITCODE -ne 0) { - throw "Could not create canonical docs worktree '$path' (exit $LASTEXITCODE)." - } - Sync-ContextCheckout -Path $path -RepositoryUrl $repo.Url -Confirm:$false | Out-Null - } catch { - $activationError = $_ - $rollbackErrors = [Collections.Generic.List[string]]::new() - if ($moved -and (Test-Path $path)) { - git --git-dir=$expectedBackingPath worktree remove --force $path 2>$null - if ($LASTEXITCODE -ne 0) { - $rollbackErrors.Add("git worktree remove failed for '$path'.") - } - try { - Remove-Item -LiteralPath $path -Recurse -Force -ErrorAction Stop - } catch { - $rollbackErrors.Add("Could not remove partial worktree '$path': $($_.Exception.Message)") - } - } - if ($moved -and -not (Test-Path $path) -and (Test-Path $backupPath)) { - try { - Move-Item -LiteralPath $backupPath -Destination $path -ErrorAction Stop - } catch { - $rollbackErrors.Add("Could not restore '$backupPath' to '$path': $($_.Exception.Message)") - } - } - if (Test-Path $expectedBackingPath) { - try { - Remove-Item -LiteralPath $expectedBackingPath -Recurse -Force -ErrorAction Stop - } catch { - $rollbackErrors.Add("Could not remove partial backing '$expectedBackingPath': $($_.Exception.Message)") - } - } - if ($rollbackErrors.Count -gt 0) { - throw "Migration activation and rollback both failed. $($rollbackErrors -join ' ') Original error: $($activationError.Exception.Message)" - } - throw "Migration activation failed for '$path'; the original clone is usable and partial backing removed. $($activationError.Exception.Message)" - } - Write-Warning "Migrated '$path' to bare+worktree layout. Verify it, then remove retained backup '$backupPath'." - } - $backingPath = $expectedBackingPath - } elseif (Test-Path $gitEntry -PathType Leaf) { - $backingPath = (git -C $path rev-parse --path-format=absolute --git-common-dir | Out-String).Trim() - if ($LASTEXITCODE -ne 0) { - throw "Cannot resolve the backing repository for docs worktree '$path'." - } - $isBare = (git --git-dir=$backingPath rev-parse --is-bare-repository | Out-String).Trim() - if ($LASTEXITCODE -ne 0 -or $isBare -ne 'true') { - throw "Docs worktree '$path' is not backed by a bare repository. Repair it before using context." - } - } elseif (Test-Path $path) { - throw "Cannot install docs at '$path': it exists but is not a supported git checkout." - } else { - $backingPath = $expectedBackingPath - if (-not (Test-Path $backingPath)) { - if ($PSCmdlet.ShouldProcess($repo.Url, "Clone bare docs backing into '$backingPath'")) { - New-Item -ItemType Directory -Path (Split-Path -Parent $backingPath) -Force | Out-Null - git clone --bare --quiet $repo.Url $backingPath - if ($LASTEXITCODE -ne 0) { - throw "Bare clone failed for $($repo.Url) (exit $LASTEXITCODE)." - } - } - } - $isBare = (git --git-dir=$backingPath rev-parse --is-bare-repository | Out-String).Trim() - if ($LASTEXITCODE -ne 0 -or $isBare -ne 'true') { - throw "Docs backing path '$backingPath' is not a bare repository." - } - $remote = Sync-ContextRemote -GitPath $backingPath -RepositoryUrl $repo.Url -Bare -Confirm:$false - Sync-BareDefaultBranch -BackingPath $backingPath -Remote $remote -Confirm:$false - if ($PSCmdlet.ShouldProcess($path, 'Create canonical docs worktree')) { - git --git-dir=$backingPath worktree add --quiet $path $remote.DefaultBranch - if ($LASTEXITCODE -ne 0) { - throw "Could not create canonical docs worktree '$path' (exit $LASTEXITCODE)." - } - } - } - - Sync-ContextCheckout -Path $path -RepositoryUrl $repo.Url -Confirm:$false | Out-Null - Set-ContextIdentity -Path $path -Name $UserName -Email $UserEmail -Confirm:$false - [pscustomobject]@{ - Repository = $repo.Name - Path = $path - BackingPath = $backingPath - Changes = $repo.Changes - } -} - -$results diff --git a/bootstrap/README.md b/bootstrap/README.md index 863de29..e937fd2 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -1,171 +1,39 @@ # Bootstrap -The single starting point for agents: a git-isolated local clone of the MSXOrg documentation repository under `~/.msxorg`, plus the instruction that sends every agent there first. +`AGENTS.template.md` is the user-global context router. Install its contents +as user-level instructions so every repository starts by locating and +synchronizing the current MSX documentation clone with Git. -## Contents +The suggested repository-local router is: -- `Initialize-MsxWorkspace.ps1` — idempotent setup. Clones `MSXOrg/docs` under `~/.msxorg`, requires the existing clone to exactly match its remote default branch, 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 points agents to the local MSXOrg docs clone. Install it once per machine (below). +```markdown +# AGENTS -## The model +This repository is `github.com/MSXOrg/`. Read in this order: -- `~/.msxorg/docs` is **read context** — the ways of working, coding standards, and agent workflow. Changes to it go through **pull requests**. -- `~/.msxorg/docs.git` is the bare backing repository for the readable, clean `~/.msxorg/docs` main worktree. -- `~/./docs.git` and `docs/` provide the same bare+main-worktree model for each organization's documentation. +1. `README.md` — what this repository is and how it builds. +2. `.github/CONTRIBUTING.md` — how a change is made and reviewed here. +3. `docs/index.md` — this repository's own documentation. +4. `~/.msxorg/docs/src/docs/index.md` — the organization standards. -Before the repository is used, bootstrap fetches it and requires a clean checkout on the remote default branch at the exact remote head. A dirty, locally ahead, diverged, wrong-branch, or unreachable context repository stops bootstrap; stale context is never treated as a successful fallback. - -Keeping the workspace separate and git-isolated means an agent reads the same documentation 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. - -The loaded `AGENTS.md` points to the roots; discovery happens in documentation. Start at `~/.msxorg/docs/src/docs/index.md`, follow Ways of Working to Workflow, infer the current stage, and read the linked procedure. Clear task language can shortcut stage selection, but no skill or instruction file owns a separate copy of the process. - -## Install (once per machine) - -Run the bootstrap: - -```powershell -$workspaceRoot = if ($env:MSX_WORKSPACE_ROOT) { $env:MSX_WORKSPACE_ROOT } else { Join-Path $HOME '.msxorg' } -$docsUrl = if ($env:MSX_DOCS_URL) { $env:MSX_DOCS_URL } else { 'https://github.com/MSXOrg/docs.git' } -$docs = Join-Path $workspaceRoot 'docs' -$docsBacking = "$docs.git" -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'))) { - if (-not (Test-Path $docsBacking)) { - New-Item -ItemType Directory -Force -Path (Split-Path -Parent $docs) | Out-Null - git clone --bare $docsUrl $docsBacking - if ($LASTEXITCODE -ne 0) { - throw "Bare clone of MSXOrg/docs failed (exit $LASTEXITCODE). Check network access and credentials." - } - } - if ((git --git-dir=$docsBacking rev-parse --is-bare-repository) -ne 'true') { - throw "$docsBacking exists but is not a bare repository." - } - if ((git --git-dir=$docsBacking remote get-url origin) -ne $docsUrl) { - throw "$docsBacking origin does not match canonical $docsUrl." - } - $refspec = '+refs/heads/*:refs/remotes/origin/*' - if ($refspec -notin @(git --git-dir=$docsBacking config --get-all remote.origin.fetch)) { - git --git-dir=$docsBacking config --add remote.origin.fetch $refspec - if ($LASTEXITCODE -ne 0) { throw "Could not configure $docsBacking." } - } - git --git-dir=$docsBacking fetch origin --prune --quiet - if ($LASTEXITCODE -ne 0) { throw "Could not refresh $docsBacking. Do not use stale context." } - git --git-dir=$docsBacking remote set-head origin --auto | Out-Null - if ($LASTEXITCODE -ne 0) { throw "Could not detect the MSXOrg/docs default branch." } - $defaultRef = (git --git-dir=$docsBacking symbolic-ref --short refs/remotes/origin/HEAD | Out-String).Trim() - if ($LASTEXITCODE -ne 0) { throw "Could not resolve origin/HEAD in $docsBacking." } - $defaultBranch = $defaultRef -replace '^origin/', '' - $remoteHead = (git --git-dir=$docsBacking rev-parse $defaultRef | Out-String).Trim() - if ($LASTEXITCODE -ne 0) { throw "Could not resolve $defaultRef in $docsBacking." } - $localRef = "refs/heads/$defaultBranch" - $localHead = (git --git-dir=$docsBacking rev-parse --verify $localRef 2>$null | Out-String).Trim() - if ($LASTEXITCODE -eq 128) { - git --git-dir=$docsBacking update-ref $localRef $remoteHead - } elseif ($LASTEXITCODE -ne 0) { - throw "Could not inspect $localRef in $docsBacking." - } elseif ($localHead -ne $remoteHead) { - git --git-dir=$docsBacking merge-base --is-ancestor $localHead $remoteHead - if ($LASTEXITCODE -ne 0) { throw "$localRef is ahead or diverged in $docsBacking." } - if ("branch $localRef" -in @(git --git-dir=$docsBacking worktree list --porcelain)) { - throw "$localRef is checked out elsewhere. Update that worktree first." - } - git --git-dir=$docsBacking update-ref $localRef $remoteHead $localHead - } - if ($LASTEXITCODE -ne 0 -or (git --git-dir=$docsBacking rev-parse $localRef) -ne $remoteHead) { - throw "$localRef is not exactly synchronized with $defaultRef." - } - git --git-dir=$docsBacking worktree add $docs $defaultBranch - if ($LASTEXITCODE -ne 0) { - throw "Could not create the canonical MSXOrg/docs worktree at $docs." - } -} else { - if ((git -C $docs remote get-url origin) -ne $docsUrl) { - throw "$docs origin does not match canonical $docsUrl." - } - $refspec = '+refs/heads/*:refs/remotes/origin/*' - if ($refspec -notin @(git -C $docs config --get-all remote.origin.fetch)) { - git -C $docs config --add remote.origin.fetch $refspec - if ($LASTEXITCODE -ne 0) { - throw "Could not configure remote tracking branches for MSXOrg/docs (exit $LASTEXITCODE)." - } - } - git -C $docs fetch origin --prune --quiet - if ($LASTEXITCODE -ne 0) { - throw "git fetch of MSXOrg/docs failed (exit $LASTEXITCODE). Do not use stale context." - } - git -C $docs remote set-head origin --auto | Out-Null - if ($LASTEXITCODE -ne 0) { throw "Could not detect the MSXOrg/docs default branch." } - $defaultRef = (git -C $docs symbolic-ref --short refs/remotes/origin/HEAD | Out-String).Trim() - if ($LASTEXITCODE -ne 0) { throw "Could not resolve origin/HEAD in $docs." } - $defaultBranch = $defaultRef -replace '^origin/', '' - $branch = (git -C $docs branch --show-current | Out-String).Trim() - if ($branch -ne $defaultBranch) { - throw "$docs is on '$branch', not '$defaultBranch'. Switch branches before using this context." - } - if (@(git -C $docs status --porcelain).Count -gt 0) { - throw "$docs has uncommitted changes. Resolve them before using this context." - } - git -C $docs merge --ff-only --quiet $defaultRef - if ($LASTEXITCODE -ne 0) { - throw "MSXOrg/docs cannot fast-forward to $defaultRef. Do not use stale context." - } - if ((git -C $docs rev-parse HEAD) -ne (git -C $docs rev-parse $defaultRef)) { - throw "$docs is not exactly synchronized with $defaultRef. Reconcile local commits before using this context." - } -} -$projects = @( - @{ - Name = 'MSXOrg' - Path = '' - DocsUrl = $docsUrl - } -) -& (Join-Path $docs 'bootstrap/Initialize-MsxWorkspace.ps1') -Root $workspaceRoot -Project $projects -if ($LASTEXITCODE -ne 0) { - throw "MSX workspace synchronization failed. Do not read context until every repository is current." -} +Read nearest first. A local file never overrides a standard. ``` -## Add project context - -The default project is MSXOrg. A repository in another project declares additional documentation coordinates in its agent installation chapter and passes them to the same bootstrap: +Repository-local `AGENTS.md` files then route from local guidance to remote +organization guidance. Client-specific files such as `.claude/CLAUDE.md` and +`.github/copilot-instructions.md` point to that router rather than duplicating +it: -```powershell -$projects = @( - @{ - Name = 'MSXOrg' - Path = '' - DocsUrl = 'https://github.com/MSXOrg/docs.git' - } - @{ - Name = 'PSModule' - Path = '' - DocsUrl = 'https://github.com/PSModule/docs.git' - } -) -& (Join-Path $docs 'bootstrap/Initialize-MsxWorkspace.ps1') -Root (Join-Path $HOME '.psmodule') -Project $projects +```markdown +# Claude Code +@../AGENTS.md ``` -Each plug-in uses the same fail-closed freshness validation. `Path` is relative to the organization workspace root, so projects can choose a collision-free location without forking the bootstrap. Run a separate workspace for each GitHub organization, such as `~/.psmodule` for PSModule. - -Existing clean simple docs clones are migrated automatically. The original clone is retained beside the new layout as `docs.simple-clone-backup` for manual verification and removal. Existing docs worktrees backed by another bare path are reused in place. Dirty, ahead, diverged, wrong-branch, conflicting-path, or otherwise unsafe layouts stop with actionable guidance before conversion. - -Docs changes use topic worktrees created from `~/.msxorg/docs.git`; never branch or work inside the canonical `~/.msxorg/docs` main worktree. - -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 - @~/.msxorg/docs/bootstrap/AGENTS.template.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 - -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. +```markdown +Follow the instructions in [AGENTS.md](../AGENTS.md). +``` -> **Override this if you are not the maintainer.** With the default, commits 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. +The shared `msxorg` Agent Plugin at +`~/.msxorg/docs/.github/plugin/marketplace.json` improves discoverability +without creating a second source of truth. Its skills are shallow pointers +from an intent to one canonical documentation page. diff --git a/src/docs/Capabilities/agentic-development/conformance.md b/src/docs/Capabilities/agentic-development/conformance.md index df6591d..00fe305 100644 --- a/src/docs/Capabilities/agentic-development/conformance.md +++ b/src/docs/Capabilities/agentic-development/conformance.md @@ -23,7 +23,7 @@ A conformant repository MUST provide all of the following. | **Reading order** | The router states the order in which context is read, from repository-local to organization-canonical | | **Client routes** | Every supported runtime's expected instruction path exists and resolves to the router, carrying no content of its own ([client behavior](design.md#client-behavior)) | | **Canonical coordinates** | The router names the organization's canonical documentation location, so context is reachable without prior knowledge | -| **Freshness** | Canonical context is refreshed at the start of every session, in every runtime ([refresh hooks](design.md#refresh-hooks)) | +| **Freshness** | Canonical context is synchronized at the start of every session, in every runtime ([context freshness](design.md#context-freshness)) | | **Precedence** | The router states that local files never override a standard | The baseline is small on purpose. Every item is something an agent needs before it can find diff --git a/src/docs/Capabilities/agentic-development/design.md b/src/docs/Capabilities/agentic-development/design.md index 2b0d7cc..8e6802d 100644 --- a/src/docs/Capabilities/agentic-development/design.md +++ b/src/docs/Capabilities/agentic-development/design.md @@ -109,7 +109,7 @@ flowchart TD host -->|"github.com/PSModule"| psmodule["PSModule context"] host -->|"any adopting org"| other["<host>/<org> context"] - msx --> refresh["Refresh selected docs
stop unless exactly synchronized"] + msx --> refresh["Synchronize selected docs with Git
stop unless exactly synchronized"] psmodule --> refresh other --> refresh refresh --> repo["Read README, CONTRIBUTING,
and local docs"] @@ -131,7 +131,7 @@ Resolution is deterministic. If the active repository remote is `github.com/PSMo ## Pointer files -`AGENTS.md` is the cross-runtime router. It names the project and lists where to read, in order. It holds nothing else — no bootstrap, no build commands, no contribution mechanics, no standards. +`AGENTS.md` is the cross-runtime router. It names the project and lists where to read, in order. It holds nothing else — no context synchronization mechanics, no build commands, no contribution mechanics, no standards. ```markdown # Agents @@ -171,56 +171,61 @@ Path-scoped instruction files are reserved for local rules that cannot live cent ## Local workspace -A local bootstrap makes central context predictable: +A local Git clone makes central context predictable: ```text ~/.msxorg/ - docs.git/ # MSXOrg/docs bare backing repository - docs/ # clean MSXOrg/docs main worktree + docs/ # clean MSXOrg/docs clone ~/.psmodule/ - docs.git/ # PSModule/docs bare backing repository - docs/ # PSModule/docs main worktree + docs/ # clean PSModule/docs clone ``` -The bootstrap clones missing repositories and fetches every existing context repository before use. Each clone must be clean, checked out on the remote default branch, and exactly equal to the fetched remote head. A dirty, locally ahead, diverged, wrong-branch, or unreachable clone stops context resolution; the agent does not use a possibly stale local copy. Bootstrap writes repository-local git configuration only. +Before context is read, the agent ensures the clone exists, fetches its remote, +and fast-forwards its default branch. Each clone must be clean, checked out on +the remote default branch, and exactly equal to the fetched remote head. A +dirty, locally ahead, diverged, wrong-branch, or unreachable clone stops context +resolution; the agent does not use a possibly stale local copy. Each GitHub organization has its own organization-named workspace root, such as `~/.msxorg` for MSXOrg or `~/.psmodule` for PSModule. Repository agent files retain the organization coordinates required before project documentation can be -reached; the reusable bootstrap behavior remains central. +reached; the user-global agent instructions explain how to prepare it with Git. -## Refresh hooks +## Context freshness -The freshness gate is only worth as much as the last time it ran. A workspace bootstrapped -once is current at that moment and progressively less so afterwards, and an agent reading a -week-old clone reads a standard that has since changed while believing it is canonical. +The freshness gate is only worth as much as the last time it ran. A clone +synchronized once is current at that moment and progressively less so +afterwards, and an agent reading a week-old clone reads a standard that has +since changed while believing it is canonical. -So the refresh runs at the **start of every session**, not once per machine. What differs -between runtimes is where the trigger hangs, never what it does: +So Git synchronization runs at the **start of every session**, not once per +machine. What differs between runtimes is where the trigger hangs, never what +it does: -| Runtime shape | Lifecycle point | How the refresh attaches | +| Runtime shape | Lifecycle point | How context freshness is established | | --- | --- | --- | -| Local interactive agent | Session start | A session-start hook in the runtime's own configuration invokes the bootstrap before the first turn. | -| Hosted or remote agent | Environment setup | The environment's setup steps run the bootstrap while the workspace is being prepared, so the agent starts against fresh context. | +| Local interactive agent | Session start | The agent fetches and fast-forwards the user-global clone before the first turn. | +| Hosted or remote agent | Environment setup | The environment's setup steps clone or synchronize the context repository while the workspace is being prepared. | | Review-time agent | Pull request event | Instructions are read from the pull request's head branch, so freshness follows the branch under review rather than a local clone. | -| Batch or scheduled agent | Job start | The job's first step is the bootstrap; a scheduled run has no earlier lifecycle point to rely on. | +| Batch or scheduled agent | Job start | The job's first step clones or synchronizes the context repository; a scheduled run has no earlier lifecycle point to rely on. | -Each of these is one **declaration** of the same behaviour. The bootstrap is a single -idempotent operation — clone what is missing, fetch what exists, verify each clone is clean, -on the remote default branch, and exactly equal to the fetched head — and a hook does -nothing but call it at the right moment. That is what makes a new runtime cheap to support: -the work is finding its lifecycle point, not writing another refresh. +Each of these is one **declaration** of the same behavior. The runtime ensures +the clone is clean, on the remote default branch, and exactly equal to the +fetched head before context is read. A runtime may use its own lifecycle hook, +or the agent may perform the Git check explicitly. -The refresh MUST be idempotent, because it runs far more often than it changes anything. A -hook that is expensive or noisy when everything is already current gets disabled, and a -disabled hook is worse than no hook, because the workspace still looks bootstrapped. +The synchronization MUST be idempotent, because it runs far more often than it +changes anything. A process that is expensive or noisy when everything is +already current gets disabled, and a disabled process is worse than no process, +because the workspace still appears synchronized. -Where a runtime offers no lifecycle point at all, the refresh MUST be invoked explicitly -before context is read. It MUST NOT be skipped on the grounds that the workspace was -bootstrapped recently; "recently" is not a state the agent can observe, and the gate exists -precisely to replace that judgement with a check. +Where a runtime offers no lifecycle point at all, Git synchronization MUST be +invoked explicitly before context is read. It MUST NOT be skipped on the +grounds that the workspace was synchronized recently; "recently" is not a state +the agent can observe, and the gate exists precisely to replace that judgment +with a check. -Each shape's obligations beyond the refresh — its entry file, tool declaration, and identity — +Each shape's obligations beyond context freshness — its entry file, tool declaration, and identity — are set out in [Runtime Integration](runtime-integration.md). ## Client behavior @@ -242,7 +247,7 @@ Because Copilot code review reads the head branch, a pull request that changes ` | Failure | Design response | | --- | --- | | Repository does not identify its organization context | Infer from remote URL; ask when ambiguous. | -| A docs clone is missing or cannot synchronize | Bootstrap or repair it, then retry. Stop context resolution until the canonical context repository passes the freshness gate. | +| A docs clone is missing or cannot synchronize | Clone or repair it with Git, then retry. Stop context resolution until the canonical context repository passes the freshness gate. | | Pointer file duplicates central standards | Replace duplicated content with a route during review. A client file holds a pointer, not a copy. | | A skill, command, named agent, or instruction file defines a workflow stage | Delete the duplicate procedure and link to Workflow or its stage page. | | Two organizations are open in one workspace | Select by active repository; ask before cross-project changes. | @@ -254,7 +259,7 @@ Because Copilot code review reads the head branch, a pull request that changes ` 1. Create or identify the organization `docs` repository. 2. Add the canonical Workflow and linked stage procedures to `docs`. 3. Add the `AGENTS.md` router to each product repository, plus a route for every client that cannot read it. -4. Add a bootstrap that keeps the local docs clone present and exactly synchronized before use. +4. Document the user-global docs clone and require Git synchronization before use. 5. Review new work for pointer discipline: facts live once, links point to them. ## Where this connects diff --git a/src/docs/Capabilities/agentic-development/index.md b/src/docs/Capabilities/agentic-development/index.md index ef8689f..35cf232 100644 --- a/src/docs/Capabilities/agentic-development/index.md +++ b/src/docs/Capabilities/agentic-development/index.md @@ -13,10 +13,10 @@ A repository adopts the framework by carrying a short router and the client rout | Page | Description | | --- | --- | -| [Spec](spec.md) | Requirements for refresh-first, index-first agentic development through canonical documentation and thin pointers. | +| [Spec](spec.md) | Requirements for fresh, index-first agentic development through canonical documentation and thin pointers. | | [Design](design.md) | How the agentic development framework is built — OKF documentation, thin repo pointers, and deterministic context resolution. | | [MCP Servers](mcp-servers.md) | How one logical set of tool servers is defined once and declared by every runtime in its own format, so a documented procedure does not depend on which client runs it. | -| [Runtime Integration](runtime-integration.md) | How a runtime is wired into the framework — the entry file it reads, the lifecycle point its refresh attaches to, the permissions it needs, and what a new runtime must supply to be supported. | +| [Runtime Integration](runtime-integration.md) | How a runtime is wired into the framework — the entry file it reads, the lifecycle point where it verifies context freshness, the permissions it needs, and what a new runtime must supply to be supported. | | [Plugin Distribution](plugin-distribution.md) | How recurring workflows are packaged as named intents that point to canonical documentation, and why a packaged shortcut never carries a copy of the procedure. | | [Plugin Marketplaces](design-plugin-marketplaces.md) | How shared and initiative-owned Agent Plugin marketplaces are named, laid out, versioned, and updated. | | [Agent Interaction](agent-interaction.md) | How humans and agents coordinate through issues, labels, and pull requests, and why intent and implementation are kept in separate artifacts. | diff --git a/src/docs/Capabilities/agentic-development/plugin-distribution.md b/src/docs/Capabilities/agentic-development/plugin-distribution.md index 32d5a58..6f70060 100644 --- a/src/docs/Capabilities/agentic-development/plugin-distribution.md +++ b/src/docs/Capabilities/agentic-development/plugin-distribution.md @@ -135,7 +135,7 @@ Bundling is tempting because it makes an intent self-contained and therefore eas distribute. It is also how the framework's central premise gets broken: a bundled procedure is a snapshot, and a snapshot distributed to many places is drift with extra steps. The canonical documentation is available to every agent through the -[freshness gate](design.md#refresh-hooks); the intent can rely on it being there and current. +[freshness gate](design.md#context-freshness); the intent can rely on it being there and current. The practical consequence is that updating a procedure needs no redistribution. The documentation changes, and every intent pointing at it is immediately correct — which is the diff --git a/src/docs/Capabilities/agentic-development/runtime-integration.md b/src/docs/Capabilities/agentic-development/runtime-integration.md index d4261ea..ddfb9cd 100644 --- a/src/docs/Capabilities/agentic-development/runtime-integration.md +++ b/src/docs/Capabilities/agentic-development/runtime-integration.md @@ -1,6 +1,6 @@ --- title: Runtime Integration -description: How a runtime is wired into the framework — the entry file it reads, the lifecycle point its refresh attaches to, the permissions it needs, and what a new runtime must supply to be supported. +description: How a runtime is wired into the framework — the entry file it reads, the lifecycle point where it verifies context freshness, the permissions it needs, and what a new runtime must supply to be supported. --- # Runtime Integration @@ -19,7 +19,7 @@ MUST supply, and nothing else. | Obligation | What it means | Where it is defined | | --- | --- | --- | | **Entry file** | The instruction file the runtime reads first, which routes to the canonical router rather than restating it | [Pointer files](design.md#pointer-files) | -| **Lifecycle point** | The moment before the first turn where the context refresh runs | [Refresh hooks](design.md#refresh-hooks) | +| **Lifecycle point** | The moment before the first turn where the runtime verifies and synchronizes context | [Context freshness](design.md#context-freshness) | | **Tool declaration** | The shared tool server set, expressed in the runtime's own configuration format | [MCP Servers](mcp-servers.md#same-contract-different-declaration-syntax) | | **Identity** | The credential the runtime authenticates with, and the permissions that identity holds | [Permissions](#permissions-follow-the-identity-not-the-runtime) | @@ -45,9 +45,8 @@ Four shapes cover the field: | **Review-time** | Triggered by a platform event on a pull request | Reads instructions from the branch under review, not from a local clone | | **Scheduled** | On a timer, with no human present | No earlier lifecycle point exists, and no one is watching a failure | -The same bootstrap, the same router, and the same tool contract serve all four. What changes -is only where the trigger hangs — which is exactly the property that makes adding a runtime -cheap. +The same Git synchronization contract, the same router, and the same tool contract serve all +four. What changes is only where synchronization runs. ### Local interactive @@ -55,11 +54,10 @@ The durable workspace is the hazard. A local runtime is the only shape whose con survives between sessions, which means it is the only shape that can read a week-old standard while believing it is canonical. -So the refresh MUST attach to a session-start lifecycle point in the runtime's own -configuration, and it MUST run before the first turn rather than on first use of context. A -refresh triggered by need is a refresh that has already been skipped once. +So Git synchronization MUST attach to a session-start lifecycle point in the runtime's own +configuration, and it MUST run before the first turn rather than on first use of context. -Where the runtime offers no session-start point, the refresh MUST be invoked explicitly +Where the runtime offers no session-start point, Git synchronization MUST be invoked explicitly before context is read. ### Hosted @@ -67,7 +65,7 @@ before context is read. A hosted runtime gets a fresh workspace per run, so staleness is not the risk — *absence* is. The environment either establishes context during setup or the agent works without it. -The refresh therefore belongs in the environment's setup steps, and setup failure MUST fail +Git synchronization therefore belongs in the environment's setup steps, and setup failure MUST fail the run. An agent that starts successfully against missing context produces work that looks finished and was never governed, which is the most expensive failure in the set because it is the one that reaches review looking normal. @@ -84,8 +82,8 @@ carefully as code, since they are live before merge. ### Scheduled -A scheduled runtime has no lifecycle point earlier than the job itself, so the bootstrap is -the job's first step. It also has no human to notice a problem, which raises the bar on +A scheduled runtime has no lifecycle point earlier than the job itself, so Git synchronization +is the job's first step. It also has no human to notice a problem, which raises the bar on failure handling: a scheduled run MUST fail loudly and MUST NOT proceed with partial context, because a silent partial run repeats on the schedule. @@ -120,7 +118,8 @@ Adding a runtime is a documentation change plus four declarations, in this order 1. Identify its **shape** from the table above; the shape determines the lifecycle point. 2. Add its **entry file** as a route to the canonical router, carrying no process content. -3. Attach the **refresh** to its lifecycle point, using the existing idempotent bootstrap. +3. Attach Git synchronization to its lifecycle point, preserving the clean, default-branch, + fast-forward-only contract. 4. Declare the **shared tool set** in the runtime's native configuration format. 5. Record the **identity** it authenticates as and the permissions that identity holds. @@ -135,7 +134,7 @@ that this runtime is special. ## Where this connects -- [Design](design.md#refresh-hooks) — the lifecycle table each shape's refresh attaches to, and the idempotence requirement. +- [Design](design.md#context-freshness) — the lifecycle table where each shape verifies context freshness. - [Design](design.md#client-behavior) — why entry files differ in filename and are identical in content. - [MCP Servers](mcp-servers.md) — the shared tool layer every runtime declares. - [Plugin Distribution](plugin-distribution.md) — named intents, which are per-runtime packaging over the same documented procedures. diff --git a/src/docs/Capabilities/agentic-development/spec.md b/src/docs/Capabilities/agentic-development/spec.md index a55f413..3170908 100644 --- a/src/docs/Capabilities/agentic-development/spec.md +++ b/src/docs/Capabilities/agentic-development/spec.md @@ -1,6 +1,6 @@ --- title: Spec -description: Requirements for refresh-first, index-first agentic development through canonical documentation and thin pointers. +description: Requirements for fresh, index-first agentic development through canonical documentation and thin pointers. --- # Agentic Development — Spec @@ -52,21 +52,21 @@ Applies to any organization that wants a shared project knowledge base for agent - **Organization is the project boundary.** The framework MUST resolve project context from the Git host and organization before resolving repository-specific context. - **Canonical docs repository.** Each adopting organization MUST have a `docs` repository that owns the reviewed knowledge base. -- **Pluggable project context.** The bootstrap MUST accept project-specific documentation coordinates and collision-free relative workspace paths without requiring a fork of its synchronization logic. +- **Predictable project context.** User-global instructions MUST identify the canonical documentation repository and its local clone path for each adopting organization. - **OKF-style documents.** Knowledge documents MUST be Markdown files with YAML frontmatter, one primary concept per page, and stable paths that act as identity. - **Small pages and indexes.** Documentation SHOULD prefer small pages, each folder SHOULD have an `index.md`, and indexes MUST let a human or agent navigate inward from the root. -- **Thin pointer files.** Product repositories MUST carry an `AGENTS.md` at the repository root that routes an agent from the repository's own files outward to the organization documentation and any inherited ecosystem documentation. It MUST be limited to that route list and the repository's own coordinates. It MUST NOT duplicate standards, workflow stages, or reusable process knowledge, and MUST NOT carry build commands, contribution mechanics, or workspace bootstrap steps, each of which has an owning file of its own. -- **Refresh-first, index-first workflow discovery.** After every canonical context repository passes the freshness gate, a human or agent MUST be able to follow the docs root index to Ways of Working, the canonical Workflow, and the procedure for the current stage. +- **Thin pointer files.** Product repositories MUST carry an `AGENTS.md` at the repository root that routes an agent from the repository's own files outward to the organization documentation and any inherited ecosystem documentation. It MUST be limited to that route list and the repository's own coordinates. It MUST NOT duplicate standards, workflow stages, or reusable process knowledge, and MUST NOT carry build commands, contribution mechanics, or context synchronization steps, each of which has an owning file of its own. +- **Refresh-first, index-first workflow discovery.** After every canonical context repository passes the Git freshness gate, a human or agent MUST be able to follow the docs root index to Ways of Working, the canonical Workflow, and the procedure for the current stage. - **Stage resolution from work.** Agents MUST infer the current stage from the prompt and current artifacts. Explicit task language MAY shortcut to the matching stage, but the shortcut MUST resolve to the canonical documentation. - **One process source.** Skills, commands, named agents, and tool-specific instruction files MUST NOT redefine Workflow stages. A client convenience MAY link to a stage procedure and add only runtime mechanics. -- **Segmentation before loading.** An agent MUST segment work by host, organization, repository, path, and task before loading project standards. The repository router MUST supply the coordinates that make this possible by naming its host and organization. The instruction to segment belongs to the user-global bootstrap, which runs before any repository file is read; a per-repository file MUST NOT restate it. +- **Segmentation before loading.** An agent MUST segment work by host, organization, repository, path, and task before loading project standards. The repository router MUST supply the coordinates that make this possible by naming its host and organization. The instruction to segment belongs to the user-global instructions, which run before any repository file is read; a per-repository file MUST NOT restate it. - **Client routes.** A runtime that cannot read `AGENTS.md` under its own filename MUST be given a route file — `.claude/CLAUDE.md`, `.github/copilot-instructions.md`, or the equivalent path for that runtime. A route file MUST contain only a pointer to `AGENTS.md` plus, at most, genuinely runtime-specific configuration that cannot be expressed as documentation. It MUST NOT restate standards, describe workflow behavior, or repeat the reading order. Duplication is a property of content rather than of filenames: a route holds nothing that can drift, so the number of route files is unconstrained while their contents are strictly limited. [Client behavior](design.md#client-behavior) names the exact set an MSX repository carries; an adopting organization MAY carry a different set for the runtimes it uses. - **Reading order and authority order are distinct.** An agent MUST read nearest context first, in the order the repository router defines. Precedence on conflict MUST run the opposite way: repository-local files MAY add nuance and narrow exceptions but MUST NOT override an organization or inherited ecosystem standard unless that standard permits a local exception. -- **Deterministic context resolution.** Agents MUST resolve context in layers: system and client policy, user preferences, the repository router, the context-repository freshness gate, repository context, path-scoped repository rules, organization docs, any inherited ecosystem docs, then current task context. +- **Deterministic context resolution.** Agents MUST resolve context in layers: system and client policy, user preferences, the repository router, the context-repository Git freshness gate, repository context, path-scoped repository rules, organization docs, any inherited ecosystem docs, then current task context. - **Local-first availability.** The docs repository SHOULD be available locally in a predictable workspace so agents can read it without relying on search or web access. -- **Fresh context before use.** Every canonical context repository MUST be fetched and exactly synchronized with its remote default branch before its contents are read. Dirty, locally ahead, diverged, wrong-branch, or unreachable repositories MUST stop context resolution rather than fall back to stale content. +- **Fresh context before use.** Every canonical context repository MUST be fetched and exactly synchronized with its remote default branch before its contents are read. Agents use Git directly; dirty, locally ahead, diverged, wrong-branch, or unreachable repositories MUST stop context resolution rather than fall back to stale content. - **Working checkouts are not context sources.** Canonical context MUST be read from the documentation repository clone that passed the freshness gate. A working checkout of the `docs` repository — one cloned in order to change it rather than to be governed by it — MUST NOT be used as a context source, whatever path it occupies, because it sits outside the gate. -- **Refresh once per session, not once per machine.** The freshness gate MUST run at the start of every agent session, in every runtime. A workspace that was synchronized at some earlier point MUST NOT be treated as current, because elapsed time is not a state the agent can observe. The refresh MUST be idempotent, so that running it when nothing has changed is cheap and silent; a refresh that is expensive or noisy at steady state gets bypassed, and a bypassed gate is worse than none because the workspace still appears synchronized. +- **Synchronize once per session, not once per machine.** The freshness gate MUST run at the start of every agent session, in every runtime. A workspace that was synchronized at some earlier point MUST NOT be treated as current, because elapsed time is not a state the agent can observe. The agent MUST use Git to synchronize it or stop when the clone cannot be safely synchronized. - **One tool layer, declared per runtime.** Where agents use external tools, the set of tool servers MUST be defined once as a logical layer and each runtime MUST declare that same set in its own native configuration format. A runtime MUST NOT define tools of its own that other runtimes lack, because a capability available in one client and absent in another makes the documented procedure conditional on which client is running it. - **Named intents stay pointer-based.** A packaged shortcut for a recurring workflow — however a runtime names it — MUST resolve to the canonical documentation for that workflow and MUST contain only the runtime mechanics needed to get there. It MUST NOT restate the procedure, since a shortcut that carries a copy of the process becomes a second, silently diverging definition of it. - **Advice and authority are separate.** An automated agent MAY analyse work and publish its conclusion as advice on the artifact under review. It MUST NOT be the thing that decides: it MUST NOT overwrite a human's decision, MUST NOT re-apply a decision a human has changed, and MUST NOT commit to the branch it is advising on. Its output is an input to the review, not a substitute for it. diff --git a/src/docs/Ways-of-Working/Git-Worktrees.md b/src/docs/Ways-of-Working/Git-Worktrees.md index 7cea80f..d5980cd 100644 --- a/src/docs/Ways-of-Working/Git-Worktrees.md +++ b/src/docs/Ways-of-Working/Git-Worktrees.md @@ -1,13 +1,13 @@ --- title: Git Worktrees -description: How agentic development is implemented locally — a bare-clone and worktree layout for working on several things at once. +description: How repository-delivery work is implemented locally — a bare-clone and worktree layout for working on several things at once. --- # Git Worktrees Git worktrees are how [agentic development](../Capabilities/agentic-development/index.md) is implemented on a local machine. They are purely a **local development** convenience: a way for one person — or a person and an agent, or several agents — to work on multiple repository-delivery leaves at the same time, without stashing, committing half-finished work, or switching branches. They change nothing about how a repository is built, reviewed, or shipped — that still happens through branches and pull requests, exactly as it would with an ordinary clone. -All repositories are set up as **bare clones with worktrees**. Each repository-delivery Task or Bug gets its own worktree — an independent working directory for one branch — so parallel work never collides. Epic and PBI aggregates, and operational Tasks without repository artifacts, do not get worktrees. +Repository-delivery workspaces are set up as **bare clones with worktrees**. Each repository-delivery Task or Bug gets its own worktree — an independent working directory for one branch — so parallel work never collides. Epic and PBI aggregates, operational Tasks without repository artifacts, and canonical documentation context clones do not get worktrees. ## Why this matters: working agentically in parallel @@ -42,7 +42,9 @@ In a single ordinary clone the opposite is forced: one branch checked out at a t - **`/`** — the canonical default-branch worktree. Kept clean and exactly synchronized for reading, diffing, and comparisons. Never directly committed to. - **`-/`** — one worktree folder per repository-delivery Task or Bug in flight, named by issue number and a short slug. The folder is a concise local path; its branch uses the required `/-` name, so the two names do not need to match. -For the central MSXOrg context, this becomes `~/.msxorg/docs.git` plus the readable `~/.msxorg/docs` main worktree. Each GitHub organization uses its own organization-named root, such as `~/.psmodule` for PSModule. +Canonical documentation context is a normal Git clone, such as +`~/.msxorg/docs` or `~/.psmodule/docs`, and is not part of this worktree +topology. The bare-clone layout applies to delivery repositories only. ## Remotes diff --git a/src/docs/Ways-of-Working/index.md b/src/docs/Ways-of-Working/index.md index cf11b58..4ae7e6e 100644 --- a/src/docs/Ways-of-Working/index.md +++ b/src/docs/Ways-of-Working/index.md @@ -24,10 +24,10 @@ This section documents the principles, processes, and norms that every contribut | [Spec-Driven Development](Spec-Driven-Development.md) | The specification is the source of truth — the spec (why and what), its design (how), and how a change moves from need to shipped. | | [Spec-Driven Development Templates](Spec-Driven-Development-Templates.md) | A copyable skeleton for every spec-driven artifact — specification, feature addendum, design, implementation doc, guide, reference, research, decision record, standard, orchestration playbook, and decisions register. | | [Evolutionary Development](Evolutionary-Development.md) | Grow software as bets under selection — variation, feedback, and survival of the fittest, run as one tight loop. | -| [Git Worktrees](Git-Worktrees.md) | How agentic development is implemented locally — a bare-clone and worktree layout for working on several things at once. | +| [Git Worktrees](Git-Worktrees.md) | How repository-delivery work is implemented locally — a bare-clone and worktree layout for working on several things at once. | | [Session Interactions](Session-Interactions.md) | Recognised phrases that steer a working session deterministically, why each is defined once as a standard rather than embedded in tool-specific files, and what an interaction may not do. | | [Organization Standard](Organization-Standard.md) | What every initiative organization must define centrally so humans and agents share the same expectations. | -| [Repository Standard](Repository-Standard.md) | The baseline files and behaviours every repository must expose so it is understandable, secure, and maintainable. | +| [Repository Standard](Repository-Standard.md) | The baseline files and behaviors every repository must expose so it is understandable, secure, and maintainable. | | [Repository Type Property](Repository-Type-Property.md) | How a multi-select "Type" custom property classifies every repository in an initiative organization and drives which org-wide controls apply to it. | | [Automation Labels](Automation-Labels.md) | Why every label that drives automation belongs to exactly one owning function, how namespacing keeps label dimensions disjoint, and why automation ignores labels it does not own. | | [Principles](Principles/index.md) | The foundational beliefs and product mindset behind every decision. | diff --git a/tests/Initialize-MsxWorkspace.Tests.ps1 b/tests/Initialize-MsxWorkspace.Tests.ps1 deleted file mode 100644 index 982b1b3..0000000 --- a/tests/Initialize-MsxWorkspace.Tests.ps1 +++ /dev/null @@ -1,61 +0,0 @@ -#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '6.0.0'; MaximumVersion = '6.*' } - -Describe 'Initialize-MsxWorkspace documentation bootstrap' { - BeforeAll { - $script:bootstrap = (Resolve-Path (Join-Path $PSScriptRoot '../bootstrap/Initialize-MsxWorkspace.ps1')).Path - $script:pwsh = (Get-Process -Id $PID).Path - - function Invoke-Bootstrap { - param([Parameter(Mandatory)] [string] $ProjectText) - - $runner = Join-Path $fixtureRoot 'run.ps1' - @" -`$projects = $ProjectText -& '$bootstrap' -Root '$workspace' -Project `$projects -UserName 'Fixture' -UserEmail 'fixture@example.invalid' -exit `$LASTEXITCODE -"@ | Set-Content $runner - & $script:pwsh -NoProfile -File $runner 2>&1 - } - } - - BeforeEach { - $fixtureRoot = Join-Path ([IO.Path]::GetTempPath()) "msx-bootstrap-$([guid]::NewGuid().ToString('N'))" - $remote = Join-Path $fixtureRoot 'docs.git' - $writer = Join-Path $fixtureRoot 'writer' - $workspace = Join-Path $fixtureRoot 'workspace' - New-Item -ItemType Directory -Path $fixtureRoot -Force | Out-Null - & git init --bare --quiet --initial-branch=main $remote - & git clone --quiet $remote $writer - & git -C $writer config user.name 'Fixture Writer' - & git -C $writer config user.email 'fixture@example.invalid' - New-Item -ItemType Directory -Path (Join-Path $writer 'bootstrap') | Out-Null - Copy-Item $script:bootstrap (Join-Path $writer 'bootstrap/Initialize-MsxWorkspace.ps1') - Set-Content (Join-Path $writer 'context.txt') 'docs context' - & git -C $writer add . - & git -C $writer commit --quiet -m 'Initialize docs' - & git -C $writer push --quiet --set-upstream origin main - $script:remote = $remote - $script:workspace = $workspace - } - - AfterEach { - if (Test-Path $fixtureRoot) { - Remove-Item $fixtureRoot -Recurse -Force - } - } - - It 'creates a bare backing repository and documentation worktree' { - Invoke-Bootstrap -ProjectText "@(@{ Name = 'Fixture'; Path = ''; DocsUrl = '$remote' })" | Out-Null - - $LASTEXITCODE | Should -Be 0 - Test-Path (Join-Path $workspace 'docs.git') | Should -BeTrue - Test-Path (Join-Path $workspace 'docs/.git') | Should -BeTrue - Test-Path (Join-Path $workspace 'docs/context.txt') | Should -BeTrue - Test-Path (Join-Path $workspace 'memory') | Should -BeFalse - } - - It 'rejects a project definition that omits documentation coordinates' { - Invoke-Bootstrap -ProjectText "@(@{ Name = 'Fixture'; Path = '' })" | Out-Null - $LASTEXITCODE | Should -Not -Be 0 - } -} From 298c8b864b4c003594c0f3c0e4e57455149f8afc Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 12:18:28 +0200 Subject: [PATCH 13/23] Use Git for context setup --- bootstrap/AGENTS.template.md | 9 ++++++++- bootstrap/README.md | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md index 28647b4..acd87e7 100644 --- a/bootstrap/AGENTS.template.md +++ b/bootstrap/AGENTS.template.md @@ -8,13 +8,20 @@ the repository's own `AGENTS.md`. Ensure `~/.msxorg/docs` is a clean clone of [`MSXOrg/docs`](https://github.com/MSXOrg/docs) before reading context: -```powershell +```sh git clone https://github.com/MSXOrg/docs.git ~/.msxorg/docs ``` If the clone already exists, use Git to fetch and fast-forward it to its default branch. If the path is not a Git clone, or it has local changes or local commits, stop and resolve that state rather than reading stale context. +Configure Git identity locally for each context clone; do not rely on global +Git configuration: + +```sh +git -C ~/.msxorg/docs config --local user.name "" +git -C ~/.msxorg/docs config --local user.email "" +``` The repository's `AGENTS.md` is the context router. It reads local guidance first — `README.md`, `.github/CONTRIBUTING.md`, and repository documentation — diff --git a/bootstrap/README.md b/bootstrap/README.md index e937fd2..48e43ac 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -4,6 +4,9 @@ as user-level instructions so every repository starts by locating and synchronizing the current MSX documentation clone with Git. +Configure Git identity locally for each context clone with `git config +--local`; do not rely on global Git configuration. + The suggested repository-local router is: ```markdown From d1c1e6b3d1a022e1e2405ff26710034a6ab36bfa Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 12:22:07 +0200 Subject: [PATCH 14/23] Keep AGENTS router title consistent --- src/docs/Capabilities/agentic-development/design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/Capabilities/agentic-development/design.md b/src/docs/Capabilities/agentic-development/design.md index 8e6802d..dba0f12 100644 --- a/src/docs/Capabilities/agentic-development/design.md +++ b/src/docs/Capabilities/agentic-development/design.md @@ -134,7 +134,7 @@ Resolution is deterministic. If the active repository remote is `github.com/PSMo `AGENTS.md` is the cross-runtime router. It names the project and lists where to read, in order. It holds nothing else — no context synchronization mechanics, no build commands, no contribution mechanics, no standards. ```markdown -# Agents +# AGENTS This repository is `github.com/MSXOrg/`. Read in this order: From 1ae908a5ad4a8e96fd69f5043915267292d2d230 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 12:24:08 +0200 Subject: [PATCH 15/23] Keep agent routers destination-only --- AGENTS.md | 4 ++-- bootstrap/README.md | 2 +- src/docs/Capabilities/agentic-development/design.md | 6 ++++-- src/docs/Capabilities/agentic-development/spec.md | 4 ++-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 8661b9e..e558a49 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ -# Agents +# AGENTS -This repository is `github.com/MSXOrg/docs`. Read in this order: +Read in this order: 1. [README.md](README.md) — what this repository is, how it is laid out, and how it builds. 2. [.github/CONTRIBUTING.md](.github/CONTRIBUTING.md) — how a change is made and reviewed here. diff --git a/bootstrap/README.md b/bootstrap/README.md index 48e43ac..a0b94be 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -12,7 +12,7 @@ The suggested repository-local router is: ```markdown # AGENTS -This repository is `github.com/MSXOrg/`. Read in this order: +Read in this order: 1. `README.md` — what this repository is and how it builds. 2. `.github/CONTRIBUTING.md` — how a change is made and reviewed here. diff --git a/src/docs/Capabilities/agentic-development/design.md b/src/docs/Capabilities/agentic-development/design.md index dba0f12..631729c 100644 --- a/src/docs/Capabilities/agentic-development/design.md +++ b/src/docs/Capabilities/agentic-development/design.md @@ -131,12 +131,14 @@ Resolution is deterministic. If the active repository remote is `github.com/PSMo ## Pointer files -`AGENTS.md` is the cross-runtime router. It names the project and lists where to read, in order. It holds nothing else — no context synchronization mechanics, no build commands, no contribution mechanics, no standards. +`AGENTS.md` is the cross-runtime router. It lists where to read, in order. It +holds nothing else — no context synchronization mechanics, no build commands, +no contribution mechanics, no standards. ```markdown # AGENTS -This repository is `github.com/MSXOrg/`. Read in this order: +Read in this order: 1. `README.md` — what this repository is and how it builds. 2. `.github/CONTRIBUTING.md` — how a change is made and reviewed here. diff --git a/src/docs/Capabilities/agentic-development/spec.md b/src/docs/Capabilities/agentic-development/spec.md index 3170908..f7bbc6e 100644 --- a/src/docs/Capabilities/agentic-development/spec.md +++ b/src/docs/Capabilities/agentic-development/spec.md @@ -55,11 +55,11 @@ Applies to any organization that wants a shared project knowledge base for agent - **Predictable project context.** User-global instructions MUST identify the canonical documentation repository and its local clone path for each adopting organization. - **OKF-style documents.** Knowledge documents MUST be Markdown files with YAML frontmatter, one primary concept per page, and stable paths that act as identity. - **Small pages and indexes.** Documentation SHOULD prefer small pages, each folder SHOULD have an `index.md`, and indexes MUST let a human or agent navigate inward from the root. -- **Thin pointer files.** Product repositories MUST carry an `AGENTS.md` at the repository root that routes an agent from the repository's own files outward to the organization documentation and any inherited ecosystem documentation. It MUST be limited to that route list and the repository's own coordinates. It MUST NOT duplicate standards, workflow stages, or reusable process knowledge, and MUST NOT carry build commands, contribution mechanics, or context synchronization steps, each of which has an owning file of its own. +- **Thin pointer files.** Product repositories MUST carry an `AGENTS.md` at the repository root that routes an agent from the repository's own files outward to the organization documentation and any inherited ecosystem documentation. It MUST be limited to that route list. It MUST NOT duplicate standards, workflow stages, or reusable process knowledge, and MUST NOT carry build commands, contribution mechanics, or context synchronization steps, each of which has an owning file of its own. - **Refresh-first, index-first workflow discovery.** After every canonical context repository passes the Git freshness gate, a human or agent MUST be able to follow the docs root index to Ways of Working, the canonical Workflow, and the procedure for the current stage. - **Stage resolution from work.** Agents MUST infer the current stage from the prompt and current artifacts. Explicit task language MAY shortcut to the matching stage, but the shortcut MUST resolve to the canonical documentation. - **One process source.** Skills, commands, named agents, and tool-specific instruction files MUST NOT redefine Workflow stages. A client convenience MAY link to a stage procedure and add only runtime mechanics. -- **Segmentation before loading.** An agent MUST segment work by host, organization, repository, path, and task before loading project standards. The repository router MUST supply the coordinates that make this possible by naming its host and organization. The instruction to segment belongs to the user-global instructions, which run before any repository file is read; a per-repository file MUST NOT restate it. +- **Segmentation before loading.** An agent MUST segment work by host, organization, repository, path, and task before loading project standards. User-global instructions and the active repository context supply the coordinates that make this possible; a per-repository router MUST NOT restate them. - **Client routes.** A runtime that cannot read `AGENTS.md` under its own filename MUST be given a route file — `.claude/CLAUDE.md`, `.github/copilot-instructions.md`, or the equivalent path for that runtime. A route file MUST contain only a pointer to `AGENTS.md` plus, at most, genuinely runtime-specific configuration that cannot be expressed as documentation. It MUST NOT restate standards, describe workflow behavior, or repeat the reading order. Duplication is a property of content rather than of filenames: a route holds nothing that can drift, so the number of route files is unconstrained while their contents are strictly limited. [Client behavior](design.md#client-behavior) names the exact set an MSX repository carries; an adopting organization MAY carry a different set for the runtimes it uses. - **Reading order and authority order are distinct.** An agent MUST read nearest context first, in the order the repository router defines. Precedence on conflict MUST run the opposite way: repository-local files MAY add nuance and narrow exceptions but MUST NOT override an organization or inherited ecosystem standard unless that standard permits a local exception. - **Deterministic context resolution.** Agents MUST resolve context in layers: system and client policy, user preferences, the repository router, the context-repository Git freshness gate, repository context, path-scoped repository rules, organization docs, any inherited ecosystem docs, then current task context. From 64e65335fce4a823eda98f9a2daa71604e5454e0 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 12:26:59 +0200 Subject: [PATCH 16/23] Document the AGENTS template format --- bootstrap/AGENTS.template.md | 70 ++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md index acd87e7..cf05551 100644 --- a/bootstrap/AGENTS.template.md +++ b/bootstrap/AGENTS.template.md @@ -1,49 +1,51 @@ -# AGENTS +# AGENTS.template.md + +This document explains the user-level `AGENTS.md` template. It is not itself +the router that agents load. Install the contents of the fenced `markdown` +block as user-level agent instructions. + +The template establishes the canonical MSX documentation context before a +repository's own instructions are read. It uses Git directly, requires a +clean and synchronized clone, and keeps Git identity configuration local to +that clone rather than relying on global configuration. -This file is installed as user-level agent instructions. It is the first -context route: it identifies the current organization's canonical `docs` -repository, makes that repository available locally, and directs the agent to -the repository's own `AGENTS.md`. +The repository's `AGENTS.md` then routes from local guidance to organization +guidance. Client-specific files such as `.claude/CLAUDE.md` and +`.github/copilot-instructions.md` point to that router. The shared `msxorg` +Agent Plugin improves discoverability through skills that are shallow pointers +to canonical documentation pages. + +````markdown +# AGENTS Ensure `~/.msxorg/docs` is a clean clone of [`MSXOrg/docs`](https://github.com/MSXOrg/docs) before reading context: ```sh +# Run this only when the clone is absent. git clone https://github.com/MSXOrg/docs.git ~/.msxorg/docs -``` -If the clone already exists, use Git to fetch and fast-forward it to its -default branch. If the path is not a Git clone, or it has local changes or -local commits, stop and resolve that state rather than reading stale context. -Configure Git identity locally for each context clone; do not rely on global -Git configuration: - -```sh +# Run these commands for an existing or newly created clone. +git -C ~/.msxorg/docs fetch --prune origin +git -C ~/.msxorg/docs pull --ff-only +git -C ~/.msxorg/docs status --porcelain git -C ~/.msxorg/docs config --local user.name "" git -C ~/.msxorg/docs config --local user.email "" ``` -The repository's `AGENTS.md` is the context router. It reads local guidance -first — `README.md`, `.github/CONTRIBUTING.md`, and repository documentation — -then routes outward to the current organization guidance in -`~/.msxorg/docs/src/docs/index.md`. Client-specific files point to that router: - -```markdown -# Claude Code -@../AGENTS.md -``` - -```markdown -Follow the instructions in [AGENTS.md](../AGENTS.md). -``` +Use the clone only when it is clean and synchronized with its remote default +branch. If the path is not a Git clone, or it has local changes, local +commits, a different branch, or a diverged history, stop and resolve that +state rather than reading stale context. Do not rely on global Git +configuration. -The first example is `.claude/CLAUDE.md`; the second is -`.github/copilot-instructions.md`. Other clients use the equivalent pointer -file they recognize. These files stay shallow so `AGENTS.md` remains the one -context route. +Read the repository's `AGENTS.md` next. It reads local guidance first — +`README.md`, `.github/CONTRIBUTING.md`, and repository documentation — then +routes outward to the current organization guidance in +`~/.msxorg/docs/src/docs/index.md`. For faster discovery, install the shared `msxorg` Agent Plugin marketplace -from `~/.msxorg/docs/.github/plugin/marketplace.json`. Its skills are also -shallow pointers: each skill routes a coding, documentation, or -ways-of-working intent to one canonical page in `MSXOrg/docs`; skills do not -copy the guidance. +from `~/.msxorg/docs/.github/plugin/marketplace.json`. Its skills route +coding, documentation, and ways-of-working intents to one canonical page in +`MSXOrg/docs`; skills do not copy the guidance. +```` From 9915ea8d5120ef5fd24cdae6a876fb93a3b6eb41 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 12:30:14 +0200 Subject: [PATCH 17/23] Make AGENTS template repository-level --- AGENTS.md | 10 +-- README.md | 2 +- bootstrap/AGENTS.template.md | 72 ++++++++----------- bootstrap/README.md | 4 +- .../agentic-development/design.md | 8 +-- .../Capabilities/agentic-development/spec.md | 4 +- 6 files changed, 40 insertions(+), 60 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e558a49..5826809 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,10 +2,6 @@ Read in this order: -1. [README.md](README.md) — what this repository is, how it is laid out, and how it builds. -2. [.github/CONTRIBUTING.md](.github/CONTRIBUTING.md) — how a change is made and reviewed here. -3. [src/docs/index.md](src/docs/index.md) — the documentation this repository owns. Follow the index inward. - -Step 3 is also the MSX organization standard, so nothing governs this repository from above it. - -Read nearest first. A local file never overrides a standard. +1. [README.md](README.md) - about the repo and what it contains +2. [.github/CONTRIBUTING.md](.github/CONTRIBUTING.md) - how a change is made and reviewed +3. [docs/index.md](docs/index.md) - the documentation this repository owns diff --git a/README.md b/README.md index 6dbebb8..36a2052 100644 --- a/README.md +++ b/README.md @@ -36,5 +36,5 @@ src/ docs/ # the documentation content includes/ # shared snippets (abbreviations, links) overrides/ # theme overrides -bootstrap/ # the user-global agent workspace setup +bootstrap/ # the repository-level AGENTS.md template ``` diff --git a/bootstrap/AGENTS.template.md b/bootstrap/AGENTS.template.md index cf05551..2b57663 100644 --- a/bootstrap/AGENTS.template.md +++ b/bootstrap/AGENTS.template.md @@ -1,51 +1,35 @@ # AGENTS.template.md -This document explains the user-level `AGENTS.md` template. It is not itself -the router that agents load. Install the contents of the fenced `markdown` -block as user-level agent instructions. - -The template establishes the canonical MSX documentation context before a -repository's own instructions are read. It uses Git directly, requires a -clean and synchronized clone, and keeps Git identity configuration local to -that clone rather than relying on global configuration. - -The repository's `AGENTS.md` then routes from local guidance to organization -guidance. Client-specific files such as `.claude/CLAUDE.md` and -`.github/copilot-instructions.md` point to that router. The shared `msxorg` -Agent Plugin improves discoverability through skills that are shallow pointers -to canonical documentation pages. +This document explains the repository-level `AGENTS.md` template. It is not +itself the router that agents load. Copy the contents of the fenced `markdown` +block into an `AGENTS.md` at the repository root. + +The router sends agents to repository-local guidance first, then to the +organization's canonical documentation clone. Prepare that clone with Git +using `git clone https://github.com/MSXOrg/docs.git ~/.msxorg/docs`, or +`git -C ~/.msxorg/docs fetch --prune origin` and +`git -C ~/.msxorg/docs pull --ff-only` when it already exists. Use it only +when it is clean and synchronized with its remote default branch. + +Configure Git identity locally for each context clone with +`git -C config --local user.name ""` and +`git -C config --local user.email ""`; do not rely on +global Git configuration. + +Client-specific files such as `.claude/CLAUDE.md` and +`.github/copilot-instructions.md` point to the repository router. The shared +`msxorg` Agent Plugin improves discoverability through skills that are shallow +pointers to canonical documentation pages. ````markdown # AGENTS -Ensure `~/.msxorg/docs` is a clean clone of -[`MSXOrg/docs`](https://github.com/MSXOrg/docs) before reading context: - -```sh -# Run this only when the clone is absent. -git clone https://github.com/MSXOrg/docs.git ~/.msxorg/docs - -# Run these commands for an existing or newly created clone. -git -C ~/.msxorg/docs fetch --prune origin -git -C ~/.msxorg/docs pull --ff-only -git -C ~/.msxorg/docs status --porcelain -git -C ~/.msxorg/docs config --local user.name "" -git -C ~/.msxorg/docs config --local user.email "" -``` - -Use the clone only when it is clean and synchronized with its remote default -branch. If the path is not a Git clone, or it has local changes, local -commits, a different branch, or a diverged history, stop and resolve that -state rather than reading stale context. Do not rely on global Git -configuration. - -Read the repository's `AGENTS.md` next. It reads local guidance first — -`README.md`, `.github/CONTRIBUTING.md`, and repository documentation — then -routes outward to the current organization guidance in -`~/.msxorg/docs/src/docs/index.md`. - -For faster discovery, install the shared `msxorg` Agent Plugin marketplace -from `~/.msxorg/docs/.github/plugin/marketplace.json`. Its skills route -coding, documentation, and ways-of-working intents to one canonical page in -`MSXOrg/docs`; skills do not copy the guidance. +Read in this order: + +1. `README.md` — what this repository is and how it builds. +2. `.github/CONTRIBUTING.md` — how a change is made and reviewed here. +3. `docs/index.md` — this repository's own documentation. +4. `~/.msxorg/docs/src/docs/index.md` — the organization standards. + +Read nearest first. A local file never overrides a standard. ```` diff --git a/bootstrap/README.md b/bootstrap/README.md index a0b94be..366d262 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -1,7 +1,7 @@ # Bootstrap -`AGENTS.template.md` is the user-global context router. Install its contents -as user-level instructions so every repository starts by locating and +`AGENTS.template.md` documents the repository-level `AGENTS.md` router. Copy +the fenced template into a repository root so agents start by locating and synchronizing the current MSX documentation clone with Git. Configure Git identity locally for each context clone with `git config diff --git a/src/docs/Capabilities/agentic-development/design.md b/src/docs/Capabilities/agentic-development/design.md index 631729c..d32a7b9 100644 --- a/src/docs/Capabilities/agentic-development/design.md +++ b/src/docs/Capabilities/agentic-development/design.md @@ -190,8 +190,8 @@ resolution; the agent does not use a possibly stale local copy. Each GitHub organization has its own organization-named workspace root, such as `~/.msxorg` for MSXOrg or `~/.psmodule` for PSModule. Repository agent files -retain the organization coordinates required before project documentation can be -reached; the user-global agent instructions explain how to prepare it with Git. +retain the organization documentation destinations, and the template explains +how to prepare them with Git. ## Context freshness @@ -206,7 +206,7 @@ it does: | Runtime shape | Lifecycle point | How context freshness is established | | --- | --- | --- | -| Local interactive agent | Session start | The agent fetches and fast-forwards the user-global clone before the first turn. | +| Local interactive agent | Session start | The agent fetches and fast-forwards the context clone before the first turn. | | Hosted or remote agent | Environment setup | The environment's setup steps clone or synchronize the context repository while the workspace is being prepared. | | Review-time agent | Pull request event | Instructions are read from the pull request's head branch, so freshness follows the branch under review rather than a local clone. | | Batch or scheduled agent | Job start | The job's first step clones or synchronizes the context repository; a scheduled run has no earlier lifecycle point to rely on. | @@ -261,7 +261,7 @@ Because Copilot code review reads the head branch, a pull request that changes ` 1. Create or identify the organization `docs` repository. 2. Add the canonical Workflow and linked stage procedures to `docs`. 3. Add the `AGENTS.md` router to each product repository, plus a route for every client that cannot read it. -4. Document the user-global docs clone and require Git synchronization before use. +4. Document the canonical docs clone and require Git synchronization before use. 5. Review new work for pointer discipline: facts live once, links point to them. ## Where this connects diff --git a/src/docs/Capabilities/agentic-development/spec.md b/src/docs/Capabilities/agentic-development/spec.md index f7bbc6e..009217c 100644 --- a/src/docs/Capabilities/agentic-development/spec.md +++ b/src/docs/Capabilities/agentic-development/spec.md @@ -52,14 +52,14 @@ Applies to any organization that wants a shared project knowledge base for agent - **Organization is the project boundary.** The framework MUST resolve project context from the Git host and organization before resolving repository-specific context. - **Canonical docs repository.** Each adopting organization MUST have a `docs` repository that owns the reviewed knowledge base. -- **Predictable project context.** User-global instructions MUST identify the canonical documentation repository and its local clone path for each adopting organization. +- **Predictable project context.** Repository-level agent instructions MUST identify the canonical documentation repository and its local clone path for each adopting organization. - **OKF-style documents.** Knowledge documents MUST be Markdown files with YAML frontmatter, one primary concept per page, and stable paths that act as identity. - **Small pages and indexes.** Documentation SHOULD prefer small pages, each folder SHOULD have an `index.md`, and indexes MUST let a human or agent navigate inward from the root. - **Thin pointer files.** Product repositories MUST carry an `AGENTS.md` at the repository root that routes an agent from the repository's own files outward to the organization documentation and any inherited ecosystem documentation. It MUST be limited to that route list. It MUST NOT duplicate standards, workflow stages, or reusable process knowledge, and MUST NOT carry build commands, contribution mechanics, or context synchronization steps, each of which has an owning file of its own. - **Refresh-first, index-first workflow discovery.** After every canonical context repository passes the Git freshness gate, a human or agent MUST be able to follow the docs root index to Ways of Working, the canonical Workflow, and the procedure for the current stage. - **Stage resolution from work.** Agents MUST infer the current stage from the prompt and current artifacts. Explicit task language MAY shortcut to the matching stage, but the shortcut MUST resolve to the canonical documentation. - **One process source.** Skills, commands, named agents, and tool-specific instruction files MUST NOT redefine Workflow stages. A client convenience MAY link to a stage procedure and add only runtime mechanics. -- **Segmentation before loading.** An agent MUST segment work by host, organization, repository, path, and task before loading project standards. User-global instructions and the active repository context supply the coordinates that make this possible; a per-repository router MUST NOT restate them. +- **Segmentation before loading.** An agent MUST segment work by host, organization, repository, path, and task before loading project standards. The active repository context supplies the coordinates that make this possible; a per-repository router MUST NOT restate them. - **Client routes.** A runtime that cannot read `AGENTS.md` under its own filename MUST be given a route file — `.claude/CLAUDE.md`, `.github/copilot-instructions.md`, or the equivalent path for that runtime. A route file MUST contain only a pointer to `AGENTS.md` plus, at most, genuinely runtime-specific configuration that cannot be expressed as documentation. It MUST NOT restate standards, describe workflow behavior, or repeat the reading order. Duplication is a property of content rather than of filenames: a route holds nothing that can drift, so the number of route files is unconstrained while their contents are strictly limited. [Client behavior](design.md#client-behavior) names the exact set an MSX repository carries; an adopting organization MAY carry a different set for the runtimes it uses. - **Reading order and authority order are distinct.** An agent MUST read nearest context first, in the order the repository router defines. Precedence on conflict MUST run the opposite way: repository-local files MAY add nuance and narrow exceptions but MUST NOT override an organization or inherited ecosystem standard unless that standard permits a local exception. - **Deterministic context resolution.** Agents MUST resolve context in layers: system and client policy, user preferences, the repository router, the context-repository Git freshness gate, repository context, path-scoped repository rules, organization docs, any inherited ecosystem docs, then current task context. From ab5febe6404fd66f77d070c590388f63f7772d66 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 12:30:32 +0200 Subject: [PATCH 18/23] Keep bootstrap guidance evergreen --- bootstrap/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/README.md b/bootstrap/README.md index 366d262..b2a6364 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -2,7 +2,7 @@ `AGENTS.template.md` documents the repository-level `AGENTS.md` router. Copy the fenced template into a repository root so agents start by locating and -synchronizing the current MSX documentation clone with Git. +synchronizing the canonical MSX documentation clone with Git. Configure Git identity locally for each context clone with `git config --local`; do not rely on global Git configuration. From 0955a020d3a4cd4146cef9c57e92c82bf3787787 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 12:35:48 +0200 Subject: [PATCH 19/23] Move AGENTS template into agentic development docs --- AGENTS.md | 6 +-- README.md | 1 - bootstrap/README.md | 42 ------------------- .../agentic-development}/AGENTS.template.md | 7 +++- .../Capabilities/agentic-development/index.md | 1 + src/zensical.toml | 1 + 6 files changed, 11 insertions(+), 47 deletions(-) delete mode 100644 bootstrap/README.md rename {bootstrap => src/docs/Capabilities/agentic-development}/AGENTS.template.md (90%) diff --git a/AGENTS.md b/AGENTS.md index 5826809..2dafcea 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,6 +2,6 @@ Read in this order: -1. [README.md](README.md) - about the repo and what it contains -2. [.github/CONTRIBUTING.md](.github/CONTRIBUTING.md) - how a change is made and reviewed -3. [docs/index.md](docs/index.md) - the documentation this repository owns +1. README.md - about the repo and what it contains +2. .github/CONTRIBUTING.md - how a change is made and reviewed +3. src/docs/index.md - the documentation this repository owns diff --git a/README.md b/README.md index 36a2052..f3dab58 100644 --- a/README.md +++ b/README.md @@ -36,5 +36,4 @@ src/ docs/ # the documentation content includes/ # shared snippets (abbreviations, links) overrides/ # theme overrides -bootstrap/ # the repository-level AGENTS.md template ``` diff --git a/bootstrap/README.md b/bootstrap/README.md deleted file mode 100644 index b2a6364..0000000 --- a/bootstrap/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# Bootstrap - -`AGENTS.template.md` documents the repository-level `AGENTS.md` router. Copy -the fenced template into a repository root so agents start by locating and -synchronizing the canonical MSX documentation clone with Git. - -Configure Git identity locally for each context clone with `git config ---local`; do not rely on global Git configuration. - -The suggested repository-local router is: - -```markdown -# AGENTS - -Read in this order: - -1. `README.md` — what this repository is and how it builds. -2. `.github/CONTRIBUTING.md` — how a change is made and reviewed here. -3. `docs/index.md` — this repository's own documentation. -4. `~/.msxorg/docs/src/docs/index.md` — the organization standards. - -Read nearest first. A local file never overrides a standard. -``` - -Repository-local `AGENTS.md` files then route from local guidance to remote -organization guidance. Client-specific files such as `.claude/CLAUDE.md` and -`.github/copilot-instructions.md` point to that router rather than duplicating -it: - -```markdown -# Claude Code -@../AGENTS.md -``` - -```markdown -Follow the instructions in [AGENTS.md](../AGENTS.md). -``` - -The shared `msxorg` Agent Plugin at -`~/.msxorg/docs/.github/plugin/marketplace.json` improves discoverability -without creating a second source of truth. Its skills are shallow pointers -from an intent to one canonical documentation page. diff --git a/bootstrap/AGENTS.template.md b/src/docs/Capabilities/agentic-development/AGENTS.template.md similarity index 90% rename from bootstrap/AGENTS.template.md rename to src/docs/Capabilities/agentic-development/AGENTS.template.md index 2b57663..ee1b70b 100644 --- a/bootstrap/AGENTS.template.md +++ b/src/docs/Capabilities/agentic-development/AGENTS.template.md @@ -1,4 +1,9 @@ -# AGENTS.template.md +--- +title: AGENTS.md Template +description: The repository-level agent router template and the guidance for applying it. +--- + +# AGENTS.md Template This document explains the repository-level `AGENTS.md` template. It is not itself the router that agents load. Copy the contents of the fenced `markdown` diff --git a/src/docs/Capabilities/agentic-development/index.md b/src/docs/Capabilities/agentic-development/index.md index 35cf232..b681eb2 100644 --- a/src/docs/Capabilities/agentic-development/index.md +++ b/src/docs/Capabilities/agentic-development/index.md @@ -15,6 +15,7 @@ A repository adopts the framework by carrying a short router and the client rout | --- | --- | | [Spec](spec.md) | Requirements for fresh, index-first agentic development through canonical documentation and thin pointers. | | [Design](design.md) | How the agentic development framework is built — OKF documentation, thin repo pointers, and deterministic context resolution. | +| [AGENTS.md Template](AGENTS.template.md) | The repository-level agent router template and the guidance for applying it. | | [MCP Servers](mcp-servers.md) | How one logical set of tool servers is defined once and declared by every runtime in its own format, so a documented procedure does not depend on which client runs it. | | [Runtime Integration](runtime-integration.md) | How a runtime is wired into the framework — the entry file it reads, the lifecycle point where it verifies context freshness, the permissions it needs, and what a new runtime must supply to be supported. | | [Plugin Distribution](plugin-distribution.md) | How recurring workflows are packaged as named intents that point to canonical documentation, and why a packaged shortcut never carries a copy of the procedure. | diff --git a/src/zensical.toml b/src/zensical.toml index 43d7dad..6e19106 100644 --- a/src/zensical.toml +++ b/src/zensical.toml @@ -168,6 +168,7 @@ nav = [ "Capabilities/agentic-development/index.md", {"Spec" = "Capabilities/agentic-development/spec.md"}, {"Design" = "Capabilities/agentic-development/design.md"}, + {"AGENTS.md Template" = "Capabilities/agentic-development/AGENTS.template.md"}, {"MCP Servers" = "Capabilities/agentic-development/mcp-servers.md"}, {"Runtime Integration" = "Capabilities/agentic-development/runtime-integration.md"}, {"Plugin Distribution" = "Capabilities/agentic-development/plugin-distribution.md"}, From 7a4e5886941fda2e609322651e987a4204b7867c Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 12:48:15 +0200 Subject: [PATCH 20/23] =?UTF-8?q?=F0=9F=93=96=20[Docs]:=20Use=20public=20r?= =?UTF-8?q?epository=20pointers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/docs/Capabilities/agentic-development/AGENTS.template.md | 2 +- src/docs/Capabilities/agentic-development/design.md | 2 +- src/docs/Capabilities/agentic-development/spec.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/docs/Capabilities/agentic-development/AGENTS.template.md b/src/docs/Capabilities/agentic-development/AGENTS.template.md index ee1b70b..25be6fe 100644 --- a/src/docs/Capabilities/agentic-development/AGENTS.template.md +++ b/src/docs/Capabilities/agentic-development/AGENTS.template.md @@ -34,7 +34,7 @@ Read in this order: 1. `README.md` — what this repository is and how it builds. 2. `.github/CONTRIBUTING.md` — how a change is made and reviewed here. 3. `docs/index.md` — this repository's own documentation. -4. `~/.msxorg/docs/src/docs/index.md` — the organization standards. +4. [MSXOrg/docs](https://github.com/MSXOrg/docs/) — the organization standards. Read nearest first. A local file never overrides a standard. ```` diff --git a/src/docs/Capabilities/agentic-development/design.md b/src/docs/Capabilities/agentic-development/design.md index d32a7b9..9f8c4da 100644 --- a/src/docs/Capabilities/agentic-development/design.md +++ b/src/docs/Capabilities/agentic-development/design.md @@ -143,7 +143,7 @@ Read in this order: 1. `README.md` — what this repository is and how it builds. 2. `.github/CONTRIBUTING.md` — how a change is made and reviewed here. 3. `docs/index.md` — this repository's own documentation. -4. `~/.msxorg/docs/src/docs/index.md` — the organization standards. +4. [MSXOrg/docs](https://github.com/MSXOrg/docs/) — the organization standards. Read nearest first. A local file never overrides a standard. ``` diff --git a/src/docs/Capabilities/agentic-development/spec.md b/src/docs/Capabilities/agentic-development/spec.md index 009217c..8c998bf 100644 --- a/src/docs/Capabilities/agentic-development/spec.md +++ b/src/docs/Capabilities/agentic-development/spec.md @@ -52,7 +52,7 @@ Applies to any organization that wants a shared project knowledge base for agent - **Organization is the project boundary.** The framework MUST resolve project context from the Git host and organization before resolving repository-specific context. - **Canonical docs repository.** Each adopting organization MUST have a `docs` repository that owns the reviewed knowledge base. -- **Predictable project context.** Repository-level agent instructions MUST identify the canonical documentation repository and its local clone path for each adopting organization. +- **Predictable project context.** Repository-level agent instructions MUST identify the canonical documentation repository with a public repository pointer for each adopting organization. - **OKF-style documents.** Knowledge documents MUST be Markdown files with YAML frontmatter, one primary concept per page, and stable paths that act as identity. - **Small pages and indexes.** Documentation SHOULD prefer small pages, each folder SHOULD have an `index.md`, and indexes MUST let a human or agent navigate inward from the root. - **Thin pointer files.** Product repositories MUST carry an `AGENTS.md` at the repository root that routes an agent from the repository's own files outward to the organization documentation and any inherited ecosystem documentation. It MUST be limited to that route list. It MUST NOT duplicate standards, workflow stages, or reusable process knowledge, and MUST NOT carry build commands, contribution mechanics, or context synchronization steps, each of which has an owning file of its own. From 36cfb171a9e44861c76ebf582fe0c2c9504de193 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 12:50:10 +0200 Subject: [PATCH 21/23] =?UTF-8?q?=F0=9F=93=96=20[Docs]:=20Keep=20checkout?= =?UTF-8?q?=20mechanics=20out=20of=20routers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../agentic-development/AGENTS.template.md | 15 +++++---------- .../Capabilities/agentic-development/design.md | 4 ++-- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/docs/Capabilities/agentic-development/AGENTS.template.md b/src/docs/Capabilities/agentic-development/AGENTS.template.md index 25be6fe..ffbaa18 100644 --- a/src/docs/Capabilities/agentic-development/AGENTS.template.md +++ b/src/docs/Capabilities/agentic-development/AGENTS.template.md @@ -10,16 +10,11 @@ itself the router that agents load. Copy the contents of the fenced `markdown` block into an `AGENTS.md` at the repository root. The router sends agents to repository-local guidance first, then to the -organization's canonical documentation clone. Prepare that clone with Git -using `git clone https://github.com/MSXOrg/docs.git ~/.msxorg/docs`, or -`git -C ~/.msxorg/docs fetch --prune origin` and -`git -C ~/.msxorg/docs pull --ff-only` when it already exists. Use it only -when it is clean and synchronized with its remote default branch. - -Configure Git identity locally for each context clone with -`git -C config --local user.name ""` and -`git -C config --local user.email ""`; do not rely on -global Git configuration. +organization's canonical documentation repository through its public URL. +Agentic runtimes and local development may materialize that repository in any +context checkout they control. Clone, freshness, and local configuration +mechanics belong to that runtime or development setup, not to this portable +router. Client-specific files such as `.claude/CLAUDE.md` and `.github/copilot-instructions.md` point to the repository router. The shared diff --git a/src/docs/Capabilities/agentic-development/design.md b/src/docs/Capabilities/agentic-development/design.md index 9f8c4da..1ffc3c3 100644 --- a/src/docs/Capabilities/agentic-development/design.md +++ b/src/docs/Capabilities/agentic-development/design.md @@ -190,8 +190,8 @@ resolution; the agent does not use a possibly stale local copy. Each GitHub organization has its own organization-named workspace root, such as `~/.msxorg` for MSXOrg or `~/.psmodule` for PSModule. Repository agent files -retain the organization documentation destinations, and the template explains -how to prepare them with Git. +retain public organization documentation destinations; runtime and development +guidance defines how a context checkout is prepared and verified. ## Context freshness From 5f02068b932e113d067f4986c0b127dd451f952d Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 12:54:35 +0200 Subject: [PATCH 22/23] =?UTF-8?q?=F0=9F=93=96=20[Docs]:=20Document=20local?= =?UTF-8?q?=20context=20preparation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/docs/Capabilities/agentic-development/AGENTS.template.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/docs/Capabilities/agentic-development/AGENTS.template.md b/src/docs/Capabilities/agentic-development/AGENTS.template.md index ffbaa18..272359a 100644 --- a/src/docs/Capabilities/agentic-development/AGENTS.template.md +++ b/src/docs/Capabilities/agentic-development/AGENTS.template.md @@ -11,6 +11,8 @@ block into an `AGENTS.md` at the repository root. The router sends agents to repository-local guidance first, then to the organization's canonical documentation repository through its public URL. +Before using a linked repository, clone it locally, keep its configuration local +to that clone, and update it from its remote. Agentic runtimes and local development may materialize that repository in any context checkout they control. Clone, freshness, and local configuration mechanics belong to that runtime or development setup, not to this portable From e79e60c758a109b3c868b444a9f8801f853a4f96 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 30 Aug 2026 12:56:25 +0200 Subject: [PATCH 23/23] =?UTF-8?q?=F0=9F=93=96=20[Docs]:=20Include=20contex?= =?UTF-8?q?t=20preparation=20in=20router?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../agentic-development/AGENTS.template.md | 3 +++ src/docs/Capabilities/agentic-development/design.md | 11 ++++++++--- src/docs/Capabilities/agentic-development/spec.md | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/docs/Capabilities/agentic-development/AGENTS.template.md b/src/docs/Capabilities/agentic-development/AGENTS.template.md index 272359a..6439a0e 100644 --- a/src/docs/Capabilities/agentic-development/AGENTS.template.md +++ b/src/docs/Capabilities/agentic-development/AGENTS.template.md @@ -33,5 +33,8 @@ Read in this order: 3. `docs/index.md` — this repository's own documentation. 4. [MSXOrg/docs](https://github.com/MSXOrg/docs/) — the organization standards. +Clone each linked repository locally, keep its configuration local to that +clone, and update it before reading it. + Read nearest first. A local file never overrides a standard. ```` diff --git a/src/docs/Capabilities/agentic-development/design.md b/src/docs/Capabilities/agentic-development/design.md index 1ffc3c3..6503215 100644 --- a/src/docs/Capabilities/agentic-development/design.md +++ b/src/docs/Capabilities/agentic-development/design.md @@ -131,9 +131,10 @@ Resolution is deterministic. If the active repository remote is `github.com/PSMo ## Pointer files -`AGENTS.md` is the cross-runtime router. It lists where to read, in order. It -holds nothing else — no context synchronization mechanics, no build commands, -no contribution mechanics, no standards. +`AGENTS.md` is the cross-runtime router. It lists where to read, in order, and +includes one instruction to prepare linked repositories before reading them. It +holds no detailed synchronization mechanics, build commands, contribution +mechanics, or standards. ```markdown # AGENTS @@ -144,6 +145,10 @@ Read in this order: 2. `.github/CONTRIBUTING.md` — how a change is made and reviewed here. 3. `docs/index.md` — this repository's own documentation. 4. [MSXOrg/docs](https://github.com/MSXOrg/docs/) — the organization standards. + +Clone each linked repository locally, keep its configuration local to that +clone, and update it before reading it. + Read nearest first. A local file never overrides a standard. ``` diff --git a/src/docs/Capabilities/agentic-development/spec.md b/src/docs/Capabilities/agentic-development/spec.md index 8c998bf..182bb0b 100644 --- a/src/docs/Capabilities/agentic-development/spec.md +++ b/src/docs/Capabilities/agentic-development/spec.md @@ -55,7 +55,7 @@ Applies to any organization that wants a shared project knowledge base for agent - **Predictable project context.** Repository-level agent instructions MUST identify the canonical documentation repository with a public repository pointer for each adopting organization. - **OKF-style documents.** Knowledge documents MUST be Markdown files with YAML frontmatter, one primary concept per page, and stable paths that act as identity. - **Small pages and indexes.** Documentation SHOULD prefer small pages, each folder SHOULD have an `index.md`, and indexes MUST let a human or agent navigate inward from the root. -- **Thin pointer files.** Product repositories MUST carry an `AGENTS.md` at the repository root that routes an agent from the repository's own files outward to the organization documentation and any inherited ecosystem documentation. It MUST be limited to that route list. It MUST NOT duplicate standards, workflow stages, or reusable process knowledge, and MUST NOT carry build commands, contribution mechanics, or context synchronization steps, each of which has an owning file of its own. +- **Thin pointer files.** Product repositories MUST carry an `AGENTS.md` at the repository root that routes an agent from the repository's own files outward to the organization documentation and any inherited ecosystem documentation. It MUST be limited to that route list and the single context-preparation instruction defined by the template. It MUST NOT duplicate standards, workflow stages, or reusable process knowledge, and MUST NOT carry detailed synchronization procedures, build commands, or contribution mechanics. - **Refresh-first, index-first workflow discovery.** After every canonical context repository passes the Git freshness gate, a human or agent MUST be able to follow the docs root index to Ways of Working, the canonical Workflow, and the procedure for the current stage. - **Stage resolution from work.** Agents MUST infer the current stage from the prompt and current artifacts. Explicit task language MAY shortcut to the matching stage, but the shortcut MUST resolve to the canonical documentation. - **One process source.** Skills, commands, named agents, and tool-specific instruction files MUST NOT redefine Workflow stages. A client convenience MAY link to a stage procedure and add only runtime mechanics.