-

70 ArcKit AI Commands

+

125 ArcKit AI Commands

Complete command reference with descriptions, example outputs, and maturity status:

+
+

Which plugin ships which command? As of v5.0.0 ArcKit splits across 7 marketplace plugins. The Tier column tells you whether a command ships in arckit (Core) or in one of the 6 community plugins:

+
    +
  • Tier = Core → ships in arckit (71 commands)
  • +
  • Tier = Community + Jurisdiction = UAEarckit-uae (12)
  • +
  • Tier = Community + Jurisdiction = Francearckit-fr (12)
  • +
  • Tier = Community + Jurisdiction = Canadaarckit-ca (12)
  • +
  • Tier = Community + Jurisdiction = EUarckit-eu (7)
  • +
  • Tier = Community + Jurisdiction = Austriaarckit-at (3)
  • +
  • Tier = Community + Jurisdiction = Australiaarckit-au (8)
  • +
+

Install only what you need: claude plugin install arckit arckit-uae picks up core + UAE. Community plugins auto-install arckit as a declared dependency. See Getting Started for install snippets.

+
+
@@ -572,6 +586,7 @@

70 ArcKit AI Commands

+
@@ -585,6 +600,7 @@

70 ArcKit AI Commands

+
@@ -600,7 +616,7 @@

70 ArcKit AI Commands

- Showing 117 of 117 commands + Showing 125 of 125 commands
@@ -1973,6 +1989,78 @@

70 ArcKit AI Commands

Experimental + + /arckit.au-e8-posture + [COMMUNITY] ASD Essential Eight ML0–ML3 maturity assessment (8 mitigation strategies) + Australian Federal Overlay + Australia + Community + — + Experimental + + + /arckit.au-pia + [COMMUNITY] Privacy Act 1988 s33D Privacy Impact Assessment (13 APPs) + Australian Federal Overlay + Australia + Community + — + Experimental + + + /arckit.au-dss + [COMMUNITY] DTA Digital Service Standard (13 criteria) compliance assessment + Australian Federal Overlay + Australia + Community + — + Experimental + + + /arckit.au-ism-controls + [COMMUNITY] ASD Information Security Manual Statement of Applicability (17 control domains) + Australian Federal Overlay + Australia + Community + — + Experimental + + + /arckit.au-ndb-playbook + [COMMUNITY] OAIC Notifiable Data Breach response playbook (Privacy Act 1988 Part IIIC) + Australian Federal Overlay + Australia + Community + — + Experimental + + + /arckit.au-pspf + [COMMUNITY] Protective Security Policy Framework (4 outcomes / 16 core requirements) + Australian Federal Overlay + Australia + Community + — + Experimental + + + /arckit.au-ai-assurance + [COMMUNITY] DTA AI Assurance Framework + Responsible AI Policy v2.0 baseline (ISO 42001 readiness, Privacy Act AI-decision notification per Dec 2026 amendments) + Australian Federal Overlay + Australia + Community + — + Experimental + + + /arckit.au-disp-attestation + [COMMUNITY] DISP Member self-attestation pack (4 domains: Governance, Personnel, Physical, Information & Cyber) — consolidates evidence from E8 + ISM + PIA + NDB + PSPF + Australian Federal Overlay + Australia + Community + — + Experimental +
diff --git a/docs/getting-started.html b/docs/getting-started.html index 5587fba7..bfac2462 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -381,11 +381,28 @@

Install Claude Code

2 -

Install ArcKit Plugin

+

Install ArcKit Plugins

/plugin marketplace add tractorjuice/arc-kit
-

Then install from the Discover tab. The plugin provides the ArcKit command set, autonomous research agents, automation hooks, and bundled MCP servers. Updates are automatic via the marketplace.

-

Lighter clone: to skip the other AI-assistant distributions in the monorepo (~100 MB), add the marketplace from your shell with sparse-checkout:

-
claude plugin marketplace add tractorjuice/arc-kit --sparse .claude-plugin arckit-claude
+

As of v5.0.0 the marketplace ships 7 plugins — install only the jurisdictions you need:

+
# Core (71 commands — UK Government civilian + generic enterprise)
+claude plugin install arckit
+
+# UK + one community overlay (e.g. UAE federal)
+claude plugin install arckit arckit-uae
+
+# Everything (125 commands across UK + UAE + FR + CA + EU + AT + AU)
+claude plugin install arckit arckit-{uae,fr,ca,eu,at,au}
+

The 6 community plugins (arckit-uae, arckit-fr, arckit-ca, arckit-eu, arckit-at, arckit-au) auto-install the arckit core plugin as a declared dependency. Updates are automatic via the marketplace.

+

Lighter clone: to skip the other AI-assistant distributions in the monorepo (~100 MB), add the marketplace with sparse-checkout. Each plugin directory you want to install is listed explicitly:

+
# Core only
+claude plugin marketplace add tractorjuice/arc-kit --sparse .claude-plugin arckit-claude
+
+# Core + UAE overlay
+claude plugin marketplace add tractorjuice/arc-kit --sparse .claude-plugin arckit-claude arckit-uae
+
+# All 7 plugins
+claude plugin marketplace add tractorjuice/arc-kit --sparse .claude-plugin \
+  arckit-claude arckit-uae arckit-fr arckit-ca arckit-eu arckit-at arckit-au
diff --git a/docs/guides/au-federal-overlay.md b/docs/guides/au-federal-overlay.md new file mode 100644 index 00000000..82a9d979 --- /dev/null +++ b/docs/guides/au-federal-overlay.md @@ -0,0 +1,163 @@ +# Australian Federal / DISP-supplier Overlay Guide + +> **Overlay Origin**: Community-contributed | **Domain co-maintainer**: @royster70 | **ArcKit Version**: [VERSION] + +The Australian Federal / DISP-supplier Overlay adds 8 community-contributed commands covering the eleven regulatory anchors that apply to Australian Federal entities and Defence-cleared suppliers (DISP Members). It is anchored on ASD Essential Eight + Information Security Manual, the DTA Digital Service Standard, the Privacy Act 1988 + 13 Australian Privacy Principles, the OAIC Notifiable Data Breach scheme, the Defence Industry Security Program (DISP, Levels 1–3), the Protective Security Policy Framework, the November 2025 Commonwealth Procurement Rules overhaul, the DTA AI Assurance Framework + Responsible AI Policy v2.0, the PGPA Act s16 financial-management duties, and IRAP for cloud-service assessment. + +The overlay closes [#424](https://github.com/tractorjuice/arc-kit/issues/424). A sibling sector recipe `au-energy` covering AESCSF, SOCI Act CIRMP, and AER ring-fencing for energy-sector / SOCI-covered critical-asset operators is drafted in [#440](https://github.com/tractorjuice/arc-kit/issues/440) but held until a sector test fixture is in place. + +--- + +## Purpose + +Five jobs in one overlay: + +1. **Make ASD's cyber stack a first-class architectural artefact**, not a security-team afterthought — Essential Eight maturity posture and ISM Statement of Applicability sit alongside requirements and HLD. +2. **Replace UK GDPR / DPA 2018 with Privacy Act 1988**, including the Tranche 1 reforms (December 2024) and the December 2026 AI-decision notification provisions. +3. **Replace UK GDS Service Standard with DTA Digital Service Standard** as the citizen-service quality gate. +4. **Make DISP Member self-attestation auditable** — the four DISP security domains (governance, personnel, physical, information & cyber) each get an evidence trail, plus FOCI declaration, supply chain, and annual board attestation. +5. **Ground AI delivery in DTA AI Assurance Framework v2.0** with explicit AI Accountable Officer designation and Privacy-Act-aligned automated-decision notification. + +--- + +## When to Use + +Use the overlay if any of the following apply to the project: + +- The contracting authority is an **Australian Federal entity** (department, agency, statutory authority) or a Commonwealth-controlled corporate entity. +- The project handles **personal information** of Australian residents and is in scope of the **Privacy Act 1988** (APP entity threshold: $3M annual turnover or any health-service provider). +- The project provides services to the **Department of Defence** or its supply chain — **DISP membership** is required for Levels 1–3 supplier accreditation. +- The system is in scope of **PSPF** (Protective Security Policy Framework) — applies to all non-corporate Commonwealth entities under PGPA Act. +- The procurement is run under the **November 2025 Commonwealth Procurement Rules** overhaul (AUD 125k SME-only thresholds, AI transparency clauses, ethical conduct in VfM). +- The project includes AI/ML/LLM in scope and is subject to the **DTA AI Assurance Framework + Responsible AI Policy v2.0** (effective December 2025) and the **NAIC Essential AI Practices ("AI6")** operational guidance. + +For non-AU projects the overlay is dormant: existing UK, MOD, EU, French, Austrian, UAE, and Canada overlays are unchanged. + +--- + +## Prerequisites + +Before running the commands, set the plugin userConfig values: + +| userConfig key | Value | +|---|---| +| `governance_framework` | `AU Federal` | +| `classification_scheme` | `PSPF` (UNOFFICIAL → TOP SECRET ladder) | +| `organisation_name` | the Federal entity name (or the contracting Defence supplier name) | +| `default_classification` | one of `UNOFFICIAL`, `OFFICIAL`, `OFFICIAL:Sensitive`, `PROTECTED`, `SECRET`, `TOP SECRET` | + +> **Note on rendering**: The PSPF classification taxonomy is applied to AU artefacts via a per-command override at the marker-resolution step (mirrors the Canadian-overlay pattern in `ca-pia.md:32`). Each `au-*` command instructs the resolver to swap the standard UK classification line for `UNOFFICIAL / OFFICIAL / OFFICIAL:Sensitive / PROTECTED / SECRET`, so the AU artefacts come out with PSPF rendering regardless of these userConfig values. The `governance_framework` and `classification_scheme` settings are still useful as documented intent (project records, downstream tooling, traceability), and a future enhancement (a dedicated `document-control-au.md` partial + extended `RENDERING.md` routing) will make them drive global rendering for **non-AU** artefacts produced inside an AU project too. Until then, set these for clarity but do not rely on them to switch the global Document Control header. + +If you are a Defence supplier rather than a Federal entity, set `organisation_name` to your supplier name and use the `au-disp-attestation` command to produce the DISP Member self-attestation pack — the rest of the overlay still applies to the project itself, with the contracting Federal entity treated as the "system owner". + +--- + +## The 8 Commands + +### Security baseline + +#### `/arckit.au-e8-posture` + +Generates an ASD Essential Eight maturity posture assessment covering all 8 mitigation strategies (Application Control, Patch Applications, Configure MS Office Macro Settings, User Application Hardening, Restrict Administrative Privileges, Patch Operating Systems, Multi-factor Authentication, Regular Backups) at maturity levels ML0 through ML3. Anchored on the ASD Essential Eight Maturity Model. Handoffs: `au-ism-controls` (E8 maturity feeds ISM Domain 9 — System Hardening), `au-disp-attestation` (E8 ML2 evidence is primary input to DISP Domain 4 — Information & Cyber Security), and `au-aescsf` in the sibling `au-energy` recipe. + +#### `/arckit.au-ism-controls` + +Generates an ASD Information Security Manual Statement of Applicability across all 17 control domains (Cyber Security Roles & Responsibilities; Cyber Security Incidents; Outsourced Services; Security Documentation; Personnel Security; Physical Security; Communications Infrastructure; Communications Systems; Enterprise Mobility; Evaluated Products; Information Technology Equipment; Media; System Hardening; System Management; System Monitoring; Software Development; Database Systems & Servers; Network Security; Cryptography; Gateways; Data Transfers). ISM extends E8 — produces the comprehensive control set on top of the mitigation baseline. Handoffs: `risk` (gaps and treatment plan), `au-pspf` (Outcome 2 — information security — instantiated by ISM), `au-disp-attestation` (cross-refs Domain 4). + +### Privacy + Incident Response + +#### `/arckit.au-pia` + +Generates a Privacy Impact Assessment under Privacy Act 1988 s33D (introduced by the Tranche 1 reforms, December 2024) including assessment against all 13 Australian Privacy Principles (APP 1 — Open and transparent management of personal information; APP 2 — Anonymity and pseudonymity; APP 3 — Collection of solicited personal information; APP 4 — Dealing with unsolicited personal information; APP 5 — Notification of collection; APP 6 — Use or disclosure; APP 7 — Direct marketing; APP 8 — Cross-border disclosure; APP 9 — Adoption / use / disclosure of government related identifiers; APP 10 — Quality of personal information; APP 11 — Security of personal information; APP 12 — Access to personal information; APP 13 — Correction of personal information). Replaces the UK `dpia` command for AU projects. Handoffs: `au-ndb-playbook` (NDB depends on PIA — APP 11 + Privacy Officer designation), `au-ai-assurance` (APP 1, 5, 10, 12 cross-refs for AI-decision notification per the December 2026 amendments), `data-model` (per-entity sensitivity), `risk`. + +#### `/arckit.au-ndb-playbook` + +Generates an OAIC Notifiable Data Breach scheme operational response playbook (Privacy Act Part IIIC). Documents the 30-day notification timeline, the eligible-data-breach assessment criteria, the OAIC reporting workflow, and the affected-individual notification template. Operational artefact — depends on `au-pia` because it requires the designated Privacy Officer (APP 1) and APP 11 control inventory from the PIA. Handoffs: `au-disp-attestation` (DISP incident reporting cross-refs NDB), `risk`. + +### Service + AI compliance + +#### `/arckit.au-dss` + +Generates a DTA Digital Service Standard conformance assessment against all 13 criteria (1. Understand user needs; 2. Solve a whole problem; 3. Provide a joined-up experience; 4. Make it simple and intuitive; 5. Use ATO/digital-government building blocks; 6. Build a multidisciplinary team; 7. Iterate and improve frequently; 8. Use open standards; 9. Make it accessible and inclusive; 10. Test the service; 11. Measure performance; 12. Provide an unbroken digital service; 13. Use trusted hosting and supplier arrangements). Replaces the UK `tcop` command for AU projects (DTA DSS is the AU equivalent of UK TCoP). Handoffs: `au-e8-posture` (Criterion 13 cross-refs E8/IRAP-assessed hosting), `au-pia` (Criterion 7 cross-refs PIA + privacy notice). + +#### `/arckit.au-pspf` + +Generates a Protective Security Policy Framework outcomes scorecard against the 4 outcomes (Security Governance; Information Security; Personnel Security; Physical Security) and 16 core requirements. PSPF Outcome 2 (Information Security) is instantiated by `au-ism-controls` — the PSPF scorecard pulls from the ISM Statement of Applicability. Handoffs: `au-disp-attestation` (DISP Domain 1 — Governance — cross-refs PSPF Outcome 1; Domain 3 — Physical — cross-refs PSPF Outcome 4), `risk`. + +#### `/arckit.au-ai-assurance` + +Generates a DTA AI Assurance Framework baseline aligned to Responsible AI Policy v2.0 (effective December 2025), incorporating ISO 42001 readiness mapping, AI Accountable Officer designation, foundation-model selection and sovereignty, AI-use disclosure requirements, and Privacy Act AI-decision notification provisions (December 2026 commencement). Also covers **AU Essential AI Practices ("AI6")** — the National AI Centre's 6 essential practices for safe and responsible AI adoption (accountability / impact assessment / risk management / information sharing / testing-and-monitoring / human control), with each practice anchored to the canonical [ai.gov.au Foundations](https://www.ai.gov.au/staying-safe-and-responsible/essential-ai-practices/guidance-ai-adoption-foundations) and [Implementation Guidance](https://www.ai.gov.au/staying-safe-and-responsible/essential-ai-practices/guidance-ai-adoption-implementation-guidance) pages. Handoffs: `au-pia` (APP cross-refs for AI-decision notification), `au-e8-posture` (DLP cross-refs), `risk` (AI-specific risks), `adr` (AI/LLM provider decision is architecturally significant). + +### DISP attestation (consolidation) + +#### `/arckit.au-disp-attestation` + +Generates a DISP Member self-attestation pack — the apex artefact for Defence-supplier scope. Consolidates the four DISP security domains (Governance & Personnel; Personnel Security; Physical Security; Information & Cyber Security) plus FOCI (Foreign Ownership, Control and Influence) declaration, supply chain assurance, and the annual board attestation. **Run last in the AU stream** — it pulls evidence from `au-e8-posture` (Domain 4), `au-ism-controls` (Domain 4 + cross-domain), `au-pia` + `au-ndb-playbook` (privacy alignment + incident reporting), and `au-pspf` (Domain 1 + Domain 3 cross-refs). Per the DISP framework, attestation level (1, 2, or 3) determines the rigour expected — Level 2 is the typical Federal-supplier baseline, Level 3 applies to higher-classification work. + +--- + +## Build recipe + +Recipe: [`au-federal.yaml`](../../arckit-au/recipes/au-federal.yaml) + +35 targets across 9 build waves + 2 post-build hooks. The recipe swaps three commands from the `uk-saas` baseline (per maintainer guidance on #424): + +- `arckit:tcop` → `arckit:au-dss` (DTA DSS replaces UK TCoP) +- `arckit:secure` → `arckit:au-e8-posture` (E8 ML2 replaces UK Secure-by-Design) +- `arckit:dpia` → `arckit:au-pia` (Privacy Act 1988 replaces UK GDPR/DPA 2018) + +The wave shape mirrors `ca-federal-fitaa` — foundation → research wave + early domain artefacts → mid-domain → late ADRs → flagship → synthesis. `AU_DISP` is the consolidation flagship in W5, depending on `AU_E8`, `AU_ISM`, `AU_PIA`, `AU_NDB`, and `AU_PSPF` having completed in earlier waves. + +To run: + +```bash +# In a Claude Code session with the ArcKit plugin enabled: +/arckit:build --recipe au-federal --plan # wave-plan dry run +/arckit:build --recipe au-federal # full build +``` + +Reference test fixture: [`arckit-test-project-v44-australian-gov`](https://github.com/tractorjuice/arckit-test-project-v44-australian-gov) — the Australian Government PoC test repo. + +--- + +## Migration from UK ladder + +If you are migrating an existing UK-classified ArcKit project to the AU overlay: + +1. Update plugin userConfig: switch `governance_framework` to `AU Federal`, `classification_scheme` to `PSPF`, and pick a `default_classification` from the PSPF taxonomy. (See the *Note on rendering* in Prerequisites — under the current per-command override approach these settings record intent; the AU artefacts get PSPF rendering through their own commands rather than via global routing.) +2. Re-run `/arckit:health` to validate the Document Control headers in any newly-generated AU artefacts against the PSPF ladder. +3. Replace UK-specific artefacts where AU equivalents exist: + - `ARC-*-DPIA-*.md` → re-generate as `ARC-*-AUPIA-*.md` via `/arckit.au-pia` + - `ARC-*-SECD-*.md` (Secure-by-Design) → re-generate as `ARC-*-AUE8-*.md` via `/arckit.au-e8-posture` + - `ARC-*-TCOP-*.md` → re-generate as `ARC-*-AUDSS-*.md` via `/arckit.au-dss` +4. Add the Defence-supplier and Federal-entity-specific artefacts: + - `/arckit.au-ism-controls` for ISM SoA + - `/arckit.au-pspf` for PSPF outcomes scorecard + - `/arckit.au-ndb-playbook` for NDB response + - `/arckit.au-ai-assurance` if AI is in scope + - `/arckit.au-disp-attestation` if Defence supply-chain accreditation is in scope +5. Run `/arckit:traceability` to refresh the cross-reference matrix. + +--- + +## Co-maintenance + +The overlay is currently solo-maintained by [@royster70](https://github.com/royster70). An Australian Federal enterprise architect (or DISP-cleared supplier architect) is being recruited as domain co-maintainer before the overlay can be re-evaluated for official-baseline promotion. If you have relevant Federal/DISP architecture experience and are interested in co-maintaining, [open an issue](https://github.com/tractorjuice/arc-kit/issues) or DM [@tractorjuice](https://github.com/tractorjuice). + +--- + +## References + +- [ASD Essential Eight Maturity Model](https://www.cyber.gov.au/resources-business-and-government/essential-cyber-security/essential-eight/essential-eight-maturity-model) +- [ASD Information Security Manual](https://www.cyber.gov.au/resources-business-and-government/essential-cyber-security/ism) +- [DTA Digital Service Standard](https://www.dta.gov.au/help-and-advice/digital-service-standard) +- [Privacy Act 1988 (Cth)](https://www.legislation.gov.au/Details/C2024C00301) +- [OAIC Notifiable Data Breach scheme](https://www.oaic.gov.au/privacy/notifiable-data-breaches) +- [Defence Industry Security Program (DISP)](https://www.defence.gov.au/business-industry/programs/defence-industry-security-program) +- [Protective Security Policy Framework (PSPF)](https://www.protectivesecurity.gov.au/) +- [Commonwealth Procurement Rules](https://www.finance.gov.au/government/procurement/commonwealth-procurement-rules) (November 2025 overhaul) +- [DTA AI Assurance Framework + Responsible AI Policy v2.0](https://www.digital.gov.au/policy/ai/policy) +- [NAIC Essential AI Practices (AI6) — Foundations](https://www.ai.gov.au/staying-safe-and-responsible/essential-ai-practices/guidance-ai-adoption-foundations) +- [NAIC Essential AI Practices — Implementation Guidance](https://www.ai.gov.au/staying-safe-and-responsible/essential-ai-practices/guidance-ai-adoption-implementation-guidance) +- [PGPA Act 2013 s16](https://www.legislation.gov.au/Details/C2024C00310) +- [Information Security Registered Assessors Program (IRAP)](https://www.cyber.gov.au/about-us/programs-and-services/irap) diff --git a/docs/guides/roles/README.md b/docs/guides/roles/README.md index d7471cc3..6abad2e8 100644 --- a/docs/guides/roles/README.md +++ b/docs/guides/roles/README.md @@ -2,7 +2,7 @@ > **Guide Origin**: Official | **ArcKit Version**: [VERSION] -Which ArcKit commands should **you** use? These guides map ArcKit's 117 commands to UK Government [DDaT Capability Framework](https://ddat-capability-framework.service.gov.uk/) roles, so you can focus on the commands relevant to your job. +Which ArcKit commands should **you** use? These guides map ArcKit's 125 commands to UK Government [DDaT Capability Framework](https://ddat-capability-framework.service.gov.uk/) roles, so you can focus on the commands relevant to your job. ## Architecture Roles diff --git a/docs/guides/roles/enterprise-architect.md b/docs/guides/roles/enterprise-architect.md index 0cb70d28..dbded30f 100644 --- a/docs/guides/roles/enterprise-architect.md +++ b/docs/guides/roles/enterprise-architect.md @@ -7,7 +7,7 @@ ## Overview -The Enterprise Architect owns the architecture governance framework and is the primary ArcKit user. All 117 commands are relevant to this role — you set up principles, define the governance lifecycle, and ensure all architecture artifacts meet organisational standards. +The Enterprise Architect owns the architecture governance framework and is the primary ArcKit user. All 125 commands are relevant to this role — you set up principles, define the governance lifecycle, and ensure all architecture artifacts meet organisational standards. ## Primary Commands diff --git a/docs/guides/uae-overlay-maintenance.md b/docs/guides/uae-overlay-maintenance.md index 4dcbe3e6..b8919d97 100644 --- a/docs/guides/uae-overlay-maintenance.md +++ b/docs/guides/uae-overlay-maintenance.md @@ -114,7 +114,7 @@ The overlay is officially maintained by the ArcKit core maintainer. A UAE-reside The role: -- Auto-requested for review on PRs touching `arckit-claude/commands/uae-*.md`, `arckit-claude/templates/uae-*-template.md`, and `.arckit/templates/uae-*-template.md`. +- Auto-requested for review on PRs touching `arckit-uae/commands/uae-*.md`, `arckit-uae/templates/uae-*-template.md`, `arckit-uae/recipes/uae-*.yaml`, and `.arckit/templates/uae-*-template.md`. - Owns the quarterly review for the Citation Register. - Confirms or rejects the six not-verified items above. - Recommends additions when new federal instruments are gazetted. diff --git a/docs/index.html b/docs/index.html index 983e90e4..faed5d2a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -4,18 +4,18 @@ - - + + - + - + ArcKit - Enterprise Architecture Governance & Vendor Procurement @@ -358,7 +358,7 @@ "@id": "https://arckit.org/#website", "name": "ArcKit", "url": "https://arckit.org", - "description": "117 AI-assisted commands for systematic, compliant architecture governance across UK, EU, France, Austria, Canada, and UAE jurisdictions.", + "description": "125 AI-assisted commands for systematic, compliant architecture governance across UK, EU, France, Austria, Canada, UAE, and Australia jurisdictions.", "publisher": { "@id": "https://arckit.org/#organization" }, "inLanguage": "en-GB" }, @@ -367,7 +367,7 @@ "@id": "https://arckit.org/", "url": "https://arckit.org/", "name": "ArcKit - Enterprise Architecture Governance & Vendor Procurement", - "description": "117 AI-assisted commands for systematic, compliant project delivery — UK Government baseline plus EU, France, Austria, Canada, and UAE community overlays.", + "description": "125 AI-assisted commands for systematic, compliant project delivery — UK Government baseline plus EU, France, Austria, Canada, UAE, and Australia community overlays.", "isPartOf": { "@id": "https://arckit.org/#website" }, "about": { "@id": "https://arckit.org/#software" }, "primaryImageOfPage": "https://arckit.org/og-image.png" @@ -381,7 +381,7 @@ "applicationCategory": "DeveloperApplication", "applicationSubCategory": "Enterprise Architecture Governance", "operatingSystem": "macOS, Linux, Windows", - "description": "ArcKit is an open-source Enterprise Architecture Governance and Vendor Procurement toolkit distributed as a plugin or extension for AI coding assistants — Claude Code, Gemini CLI, GitHub Copilot, OpenAI Codex CLI, and OpenCode CLI. It provides 117 slash commands (71 official UK Government baseline plus 46 community-contributed overlays for the EU, France, Austria, Canada, and the UAE) that generate architecture artefacts using versioned templates with full traceability.", + "description": "ArcKit is an open-source Enterprise Architecture Governance and Vendor Procurement toolkit distributed as a plugin or extension for AI coding assistants — Claude Code, Gemini CLI, GitHub Copilot, OpenAI Codex CLI, and OpenCode CLI. It provides 125 slash commands (71 official UK Government baseline plus 54 community-contributed overlays for the EU, France, Austria, Canada, the UAE, and Australia) that generate architecture artefacts using versioned templates with full traceability.", "softwareVersion": "4.21.0", "license": "https://github.com/tractorjuice/arc-kit/blob/main/LICENSE", "codeRepository": "https://github.com/tractorjuice/arc-kit", @@ -400,7 +400,8 @@ "French compliance: SecNumCloud, ANSSI, EBIOS, CNIL, DINUM, PSSI", "Austrian compliance: DSG/DSGVO, NISG, BVergG", "Canada Federal compliance: FITAA, Privacy Act PIA, ATIP, AIA, ITSG-33, GC Digital Standards", - "UAE Federal compliance: PDPL, IAS, AI Charter, sovereign cloud residency, UAE Pass" + "UAE Federal compliance: PDPL, IAS, AI Charter, sovereign cloud residency, UAE Pass", + "Australian Federal / DISP-supplier compliance: ASD Essential Eight, ISM, DTA Digital Service Standard, Privacy Act 1988 PIA, OAIC NDB, PSPF, AI Assurance, DISP attestation" ] }, { @@ -412,7 +413,7 @@ "name": "What is ArcKit?", "acceptedAnswer": { "@type": "Answer", - "text": "ArcKit is an open-source Enterprise Architecture Governance and Vendor Procurement toolkit. It provides 117 AI-assisted slash commands (71 official plus 46 community-contributed overlays) that turn architecture governance from scattered documents into a systematic, template-driven workflow with full traceability from stakeholders through requirements to design and tests." + "text": "ArcKit is an open-source Enterprise Architecture Governance and Vendor Procurement toolkit. It provides 125 AI-assisted slash commands (71 official plus 54 community-contributed overlays) that turn architecture governance from scattered documents into a systematic, template-driven workflow with full traceability from stakeholders through requirements to design and tests." } }, { @@ -428,7 +429,7 @@ "name": "Which jurisdictions and compliance frameworks does ArcKit cover?", "acceptedAnswer": { "@type": "Answer", - "text": "The official baseline covers UK Government frameworks: GDS Service Standard, Technology Code of Practice, Secure by Design, NCSC Cyber Assessment Framework, HM Treasury Orange and Green Books, and G-Cloud/DOS procurement. Community-maintained overlays add the European Union (GDPR, NIS2, AI Act, DORA, CRA, DSA, Data Act), France (SecNumCloud, ANSSI, EBIOS, CNIL, DINUM, PSSI), Austria (DSG/DSGVO, NISG, BVergG), Canada Federal (FITAA, Privacy Act PIA, ATIP, AIA, ITSG-33, GC Digital Standards), and the UAE Federal (PDPL, IAS, AI Charter, sovereign cloud residency, UAE Pass)." + "text": "The official baseline covers UK Government frameworks: GDS Service Standard, Technology Code of Practice, Secure by Design, NCSC Cyber Assessment Framework, HM Treasury Orange and Green Books, and G-Cloud/DOS procurement. Community-maintained overlays add the European Union (GDPR, NIS2, AI Act, DORA, CRA, DSA, Data Act), France (SecNumCloud, ANSSI, EBIOS, CNIL, DINUM, PSSI), Austria (DSG/DSGVO, NISG, BVergG), Canada Federal (FITAA, Privacy Act PIA, ATIP, AIA, ITSG-33, GC Digital Standards), the UAE Federal (PDPL, IAS, AI Charter, sovereign cloud residency, UAE Pass), and Australian Federal / DISP-supplier (ASD Essential Eight, ISM, DTA Digital Service Standard, Privacy Act 1988 PIA, OAIC NDB, PSPF, AI Assurance, DISP attestation)." } }, { @@ -514,7 +515,7 @@

ArcKit

-
117
+
125
AI Commands
@@ -535,7 +536,7 @@

ArcKit

What is ArcKit?

-

117 AI-assisted commands that generate complete governance documents — from stakeholder analysis and risk registers to design reviews and traceability matrices. Each command produces template-driven, audit-ready artifacts. The UK Government baseline (71 core commands) ships alongside community-contributed overlays for the EU, France, Austria, Canada, and UAE.

+

125 AI-assisted commands that generate complete governance documents — from stakeholder analysis and risk registers to design reviews and traceability matrices. Each command produces template-driven, audit-ready artifacts. The UK Government baseline (71 core commands) ships alongside community-contributed overlays for the EU, France, Austria, Canada, UAE, and Australia.

@@ -597,7 +598,7 @@

Live

Jurisdictions covered

-

ArcKit ships a UK Government baseline alongside five community-contributed jurisdictional overlays. Use the command reference to filter by jurisdiction or tier — every overlay command is badged [COMMUNITY] and excluded from the official-tier count.

+

ArcKit ships a UK Government baseline alongside six community-contributed jurisdictional overlays. Use the command reference to filter by jurisdiction or tier — every overlay command is badged [COMMUNITY] and excluded from the official-tier count.

-

Browse all 117 commands →

+

Browse all 125 commands →

@@ -675,7 +682,7 @@

gov-landscape

Works with your AI

-

All 71 core commands plus 46 community overlays (117 total) produce identical outputs across AI systems. Choose the platform that fits your workflow.

+

All 71 core commands plus 54 community overlays (125 total) produce identical outputs across AI systems. Choose the platform that fits your workflow.

@@ -982,7 +989,7 @@

Explore

AI Commands

-

Browse all 117 commands (71 core + 46 community overlays) across 13 baseline categories and 5 community overlay categories. Filter by jurisdiction, tier, status, or category.

+

Browse all 125 commands (71 core + 54 community overlays) across 13 baseline categories and 6 community overlay categories. Filter by jurisdiction, tier, status, or category.

Guides

diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh index 521f13db..9c767b0c 100755 --- a/scripts/bump-version.sh +++ b/scripts/bump-version.sh @@ -77,11 +77,46 @@ jq --arg v "$NEW_VERSION" '.version = $v' arckit-claude/.claude-plugin/plugin.js mv arckit-claude/.claude-plugin/plugin.json.tmp arckit-claude/.claude-plugin/plugin.json update_file "arckit-claude/.claude-plugin/plugin.json" ".version" -# ── 8. .claude-plugin/marketplace.json (plugins[0].version only) ─────────── +# ── 8. .claude-plugin/marketplace.json (all 6 plugin entries) ────────────── +# +# All 6 plugins (arckit core + 5 community: uae, fr, ca, eu, at) share one +# version per the v5.0.0 split design. metadata.version stays at 1.0.0. -jq --arg v "$NEW_VERSION" '.plugins[0].version = $v' .claude-plugin/marketplace.json > .claude-plugin/marketplace.json.tmp +jq --arg v "$NEW_VERSION" '.plugins |= map(.version = $v)' .claude-plugin/marketplace.json > .claude-plugin/marketplace.json.tmp mv .claude-plugin/marketplace.json.tmp .claude-plugin/marketplace.json -update_file ".claude-plugin/marketplace.json" ".plugins[0].version (metadata.version unchanged)" +update_file ".claude-plugin/marketplace.json" "all .plugins[].version (metadata.version unchanged)" + +# ── 8a–8f. Community plugin manifests + VERSION files ───────────────────── +# +# Each community plugin pins its `arckit` dependency to the current core +# version with an exact (`=`) semver constraint. bump-version.sh keeps +# .version AND .dependencies[arckit].version in lockstep so the 6 plugins +# always ship as a coherent set. + +for jurisdiction in uae fr ca eu at au; do + manifest="arckit-${jurisdiction}/.claude-plugin/plugin.json" + version_file="arckit-${jurisdiction}/VERSION" + if [[ -f "$manifest" ]]; then + jq --arg v "$NEW_VERSION" ' + .version = $v + | .dependencies = ( + (.dependencies // []) + | map( + if type == "object" and .name == "arckit" + then .version = "=" + $v + else . + end + ) + ) + ' "$manifest" > "${manifest}.tmp" + mv "${manifest}.tmp" "$manifest" + update_file "$manifest" ".version + .dependencies[arckit].version" + fi + if [[ -f "$version_file" ]]; then + echo "$NEW_VERSION" > "$version_file" + update_file "$version_file" "overwrite" + fi +done # ── 9. arckit-gemini/VERSION ─────────────────────────────────────────────── @@ -132,17 +167,21 @@ echo "" echo "── Verification ──" echo "" echo "VERSION files:" -grep -H "$NEW_VERSION" VERSION arckit-claude/VERSION arckit-gemini/VERSION arckit-opencode/VERSION arckit-codex/VERSION arckit-copilot/VERSION arckit-paperclip/VERSION +grep -H "$NEW_VERSION" VERSION arckit-claude/VERSION arckit-uae/VERSION arckit-fr/VERSION arckit-ca/VERSION arckit-eu/VERSION arckit-at/VERSION arckit-gemini/VERSION arckit-opencode/VERSION arckit-codex/VERSION arckit-copilot/VERSION arckit-paperclip/VERSION echo "" echo "pyproject.toml:" grep "^version" pyproject.toml echo "" -echo "plugin.json:" -jq -r '.version' arckit-claude/.claude-plugin/plugin.json +echo "plugin.json (all 6 plugins):" +for src in arckit-claude arckit-uae arckit-fr arckit-ca arckit-eu arckit-at; do + if [[ -f "$src/.claude-plugin/plugin.json" ]]; then + printf " %-22s %s\n" "$src/plugin.json:" "$(jq -r '.version' "$src/.claude-plugin/plugin.json")" + fi +done echo "" echo "marketplace.json:" -echo " plugins[0].version: $(jq -r '.plugins[0].version' .claude-plugin/marketplace.json)" echo " metadata.version: $(jq -r '.metadata.version' .claude-plugin/marketplace.json) (should be 1.0.0)" +jq -r '.plugins[] | " \(.name): \(.version)"' .claude-plugin/marketplace.json | sed 's/^/ /' echo "" # Lint check diff --git a/scripts/check_doctype_collisions.py b/scripts/check_doctype_collisions.py new file mode 100755 index 00000000..1d285d96 --- /dev/null +++ b/scripts/check_doctype_collisions.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +"""Assert that every doc-type code in arckit-claude/config/doc-types.mjs is unique. + +No JS parser dependency — use a regex on the keys of the KNOWN_TYPES object. +The format is stable: + 'CODE': { name: '...', category: '...', regime: '...' } +""" +import re +import sys +from pathlib import Path + +src = Path("arckit-claude/config/doc-types.mjs").read_text() +codes = re.findall(r"^\s*'([A-Z][A-Z0-9_-]*)':\s*\{", src, re.MULTILINE) + +if not codes: + print("FAIL: no doc-type codes found — regex may be out of date", file=sys.stderr) + sys.exit(2) + +seen = {} +collisions = [] +for c in codes: + if c in seen: + collisions.append(c) + seen[c] = seen.get(c, 0) + 1 + +if collisions: + print(f"FAIL: duplicate doc-type codes: {sorted(set(collisions))}", file=sys.stderr) + sys.exit(1) + +print(f"OK: {len(codes)} unique doc-type code(s)") diff --git a/scripts/check_recipes.py b/scripts/check_recipes.py new file mode 100755 index 00000000..007a02f1 --- /dev/null +++ b/scripts/check_recipes.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +"""Validate every arckit-*/recipes/*.yaml file. + +Checks: +- parses as YAML +- has the required top-level keys (recipe, schema_version, targets, defaults.version) +- has unique target IDs within the recipe +- every target's `deps:` entries resolve to other target IDs in the same recipe + (glob patterns like "ADR-*" are accepted if at least one target matches) + +Exits non-zero if any check fails. Prints a one-line summary on success. +""" +import sys +import glob +import fnmatch + +try: + import yaml +except ImportError: + print("ERROR: pyyaml not installed. Run: pip install pyyaml", file=sys.stderr) + sys.exit(2) + +REQUIRED_TOP_KEYS = {"recipe", "schema_version", "targets", "defaults"} + +errors = [] +recipes_checked = 0 + +paths = sorted( + glob.glob("arckit-*/recipes/*.yaml") + + glob.glob("arckit-claude/skills/arckit-build/recipes/*.yaml") +) + +for path in paths: + try: + with open(path) as f: + data = yaml.safe_load(f) + except yaml.YAMLError as e: + errors.append(f"{path}: YAML parse error: {e}") + continue + + if not isinstance(data, dict): + errors.append(f"{path}: top-level must be a mapping") + continue + + missing = REQUIRED_TOP_KEYS - set(data.keys()) + if missing: + errors.append(f"{path}: missing required keys: {sorted(missing)}") + continue + + if "version" not in data.get("defaults", {}): + errors.append(f"{path}: defaults.version is required") + + targets = data.get("targets", []) + if not isinstance(targets, list): + errors.append(f"{path}: targets must be a list") + continue + + target_ids = [] + for t in targets: + if not isinstance(t, dict) or "id" not in t: + errors.append(f"{path}: target missing id field: {t!r}") + continue + target_ids.append(t["id"]) + + seen = set() + for tid in target_ids: + if tid in seen: + errors.append(f"{path}: duplicate target id: {tid}") + seen.add(tid) + + target_id_set = set(target_ids) + for t in targets: + if not isinstance(t, dict): + continue + for dep in t.get("deps") or []: + if "*" in dep: + if not any(fnmatch.fnmatch(tid, dep) for tid in target_id_set): + errors.append( + f"{path}: target {t.get('id')}: glob dep {dep!r} matches no target" + ) + elif dep not in target_id_set: + errors.append( + f"{path}: target {t.get('id')}: dep {dep!r} not a target in this recipe" + ) + + recipes_checked += 1 + +if errors: + print(f"FAIL: {len(errors)} error(s) across {recipes_checked} recipe(s):", file=sys.stderr) + for e in errors: + print(f" {e}", file=sys.stderr) + sys.exit(1) + +print(f"OK: {recipes_checked} recipe(s) validated") diff --git a/scripts/converter.py b/scripts/converter.py index fe1e0d66..39acebfe 100644 --- a/scripts/converter.py +++ b/scripts/converter.py @@ -203,6 +203,27 @@ def codex_skill_invocation(command_name): ) +# --- Plugin source directories merged into each non-Claude extension output --- +# +# After the v5.0.0 plugin split, commands live across 6 directories. Non-Claude +# extensions stay monolithic (per the v5 spec), so the converter walks every +# source and merges into one output per format. +# +# Order: community plugins first, core last. Filenames are jurisdiction-prefixed +# (uae-*, fr-*, ca-*, eu-*, at-*) so collisions don't happen, but if they ever +# did, core-last means core wins. + +PLUGIN_SOURCES = [ + "arckit-uae", + "arckit-fr", + "arckit-ca", + "arckit-eu", + "arckit-at", + "arckit-au", + "arckit-claude", # core last +] + + # --- Agent configuration: adding a new AI target = adding a dictionary entry --- AGENT_CONFIG = { @@ -397,11 +418,19 @@ def read_template_for_command(name, templates_dir): return None -def convert(commands_dir, agents_dir): +def convert(commands_dirs, agents_dir): """Convert plugin commands to all configured AI agent formats. - Reads each plugin command once, resolves agent prompts once, then - writes output formats with appropriate path rewriting driven by AGENT_CONFIG. + Reads each plugin command once across all source directories, resolves + agent prompts once, then writes output formats with appropriate path + rewriting driven by AGENT_CONFIG. + + Args: + commands_dirs: List of source command directories to merge + (e.g. ["arckit-uae/commands/", ..., "arckit-claude/commands/"]). + Multiple sources land in the same monolithic extension output per + the v5.0.0 plugin split design. + agents_dir: Single agents directory (agents stay in core). """ # Commands that depend on Claude Code-only features (parallel Agent dispatch, # plugin skills, etc.). Skipped when generating non-Claude formats because @@ -421,10 +450,35 @@ def convert(commands_dir, agents_dir): counts = {agent_id: 0 for agent_id in AGENT_CONFIG} paperclip_entries = [] - for filename in sorted(os.listdir(commands_dir)): - if not filename.endswith(".md"): + # Build merged file list across all plugin sources. Each entry is + # (commands_dir, filename) so per-source path lookups (templates, + # standalone overrides) resolve against the correct plugin's tree. + merged_files = [] + seen_filenames = set() + for commands_dir in commands_dirs: + if not os.path.isdir(commands_dir): continue + for filename in sorted(os.listdir(commands_dir)): + if not filename.endswith(".md"): + continue + if filename in seen_filenames: + # Collision (community vs core, or community vs community). + # Filenames are jurisdiction-prefixed so this shouldn't + # happen in practice; warn loudly if it does. + print( + f" WARNING: duplicate filename {filename} in {commands_dir} " + f"— skipping (first occurrence wins)" + ) + continue + seen_filenames.add(filename) + merged_files.append((commands_dir, filename)) + # Sort by filename so extension output order doesn't depend on the + # PLUGIN_SOURCES iteration order (paperclip's commands.json ordering + # was previously alphabetical across all commands; preserve that). + merged_files.sort(key=lambda entry: entry[1]) + + for commands_dir, filename in merged_files: if filename in claude_only_commands: print(f" Skipped Claude-only command: {filename}") continue @@ -573,14 +627,24 @@ def convert(commands_dir, agents_dir): return counts -def copy_extension_files(plugin_dir): - """Copy supporting files from plugin to all extension directories. +def copy_extension_files(plugin_sources): + """Copy supporting files from all plugin sources to extension directories. + + After the v5.0.0 plugin split, `templates/` lives in 6 different source + directories (one per plugin). Non-Claude extensions stay monolithic, so + templates from every source are merged into one `templates/` per extension. + Other directories (scripts, guides, config, schemas, skills, references) + only exist in `arckit-claude` and are copied from there. - Copies templates, scripts, guides, and skills so the extensions are - self-contained when published as separate repos. + Args: + plugin_sources: List of plugin source dirs (e.g. ["arckit-uae", ..., + "arckit-claude"]). The last entry MUST be the core plugin + ("arckit-claude") since that's where scripts/guides/etc. live. """ - copies = [ - ("templates", "templates"), + core_plugin_dir = plugin_sources[-1] + + # Categories that exist only in the core plugin and are copied from there. + core_only_copies = [ ("scripts/bash", "scripts/bash"), ("scripts/python", "scripts/python"), ("scripts/validate-handoff.mjs", "scripts/validate-handoff.mjs"), @@ -603,10 +667,40 @@ def copy_extension_files(plugin_dir): continue copy_scripts = config.get("copy_scripts_to_extension", True) print(f"Copying to {config['name']} extension ({ext_dir})...") - for src_rel, dst_rel in copies: + + # Merge templates from every plugin source into one templates/ dir. + ext_templates_dir = os.path.join(ext_dir, "templates") + if os.path.isdir(ext_templates_dir): + shutil.rmtree(ext_templates_dir) + os.makedirs(ext_templates_dir, exist_ok=True) + merged_template_count = 0 + for src_plugin in plugin_sources: + src_templates = os.path.join(src_plugin, "templates") + if not os.path.isdir(src_templates): + continue + for entry in os.listdir(src_templates): + src_path = os.path.join(src_templates, entry) + dst_path = os.path.join(ext_templates_dir, entry) + if os.path.isfile(src_path): + shutil.copy2(src_path, dst_path) + merged_template_count += 1 + elif os.path.isdir(src_path): + if os.path.isdir(dst_path): + shutil.rmtree(dst_path) + shutil.copytree(src_path, dst_path) + merged_template_count += sum( + len(files) for _, _, files in os.walk(dst_path) + ) + print( + f" Merged templates from {len(plugin_sources)} plugin source(s) " + f"-> {ext_templates_dir} ({merged_template_count} files)" + ) + + # Core-only categories + for src_rel, dst_rel in core_only_copies: if not copy_scripts and src_rel.startswith("scripts/"): continue - src = os.path.join(plugin_dir, src_rel) + src = os.path.join(core_plugin_dir, src_rel) dst = os.path.join(ext_dir, dst_rel) if os.path.isdir(src): if os.path.isdir(dst): @@ -1464,15 +1558,22 @@ def generate_copilot_instructions(output_path): if __name__ == "__main__": - commands_dir = "arckit-claude/commands/" + commands_dirs = [os.path.join(src, "commands") for src in PLUGIN_SOURCES] agents_dir = "arckit-claude/agents/" - plugin_dir = "arckit-claude" + plugin_dir = "arckit-claude" # for downstream functions that only touch core print( "Converting plugin commands to Codex, OpenCode, Gemini, and Copilot extension formats..." ) print() - print(f"Source: {commands_dir}") + print(f"Sources: {len(PLUGIN_SOURCES)} plugin dirs") + for src in PLUGIN_SOURCES: + cmd_count = ( + len([f for f in os.listdir(os.path.join(src, "commands")) + if f.endswith(".md")]) + if os.path.isdir(os.path.join(src, "commands")) else 0 + ) + print(f" {src}: {cmd_count} commands") print(f"Agents: {agents_dir}") for config in AGENT_CONFIG.values(): ext_dir = config.get("extension_dir") @@ -1483,10 +1584,10 @@ def generate_copilot_instructions(output_path): # Copy extension supporting files BEFORE convert so reference skills # are in place before command skills are generated on top print("Copying extension supporting files...") - copy_extension_files(plugin_dir) + copy_extension_files(PLUGIN_SOURCES) print() - counts = convert(commands_dir, agents_dir) + counts = convert(commands_dirs, agents_dir) # Post-processing: copy commands and agents to extension directories for agent_id, config in AGENT_CONFIG.items(): diff --git a/scripts/tag-plugins.sh b/scripts/tag-plugins.sh new file mode 100755 index 00000000..be278df7 --- /dev/null +++ b/scripts/tag-plugins.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +set -euo pipefail + +# tag-plugins.sh — Create per-plugin Claude Code native tags after the umbrella tag. +# +# The umbrella tag `vX.Y.Z` triggers `.github/workflows/release.yml`. Each +# individual plugin also gets a native tag `--vX.Y.Z` for the +# Claude Code plugin system's bookkeeping (resolving exact versions from +# marketplace history, etc.). +# +# Usage: ./scripts/tag-plugins.sh +# Example: ./scripts/tag-plugins.sh 5.0.0 + +VERSION="${1:-}" +if [[ -z "$VERSION" ]]; then + echo "Usage: $0 " >&2 + echo "Example: $0 5.0.0" >&2 + exit 1 +fi + +if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Error: version must be semver (X.Y.Z), got: $VERSION" >&2 + exit 1 +fi + +PLUGINS=(arckit-claude arckit-uae arckit-fr arckit-ca arckit-eu arckit-at arckit-au) + +CREATED=0 +SKIPPED=0 + +for plugin_dir in "${PLUGINS[@]}"; do + manifest="$plugin_dir/.claude-plugin/plugin.json" + if [[ ! -f "$manifest" ]]; then + echo "Skipping $plugin_dir (no manifest)" >&2 + continue + fi + plugin_name=$(python3 -c "import json; print(json.load(open('$manifest'))['name'])") + tag="${plugin_name}--v${VERSION}" + + if git rev-parse "$tag" >/dev/null 2>&1; then + echo "Tag $tag already exists, skipping" + SKIPPED=$((SKIPPED + 1)) + continue + fi + + echo "Creating tag $tag" + git tag -a "$tag" -m "$plugin_name $VERSION" + git push origin "$tag" + CREATED=$((CREATED + 1)) +done + +echo "" +echo "Done — created $CREATED native plugin tag(s), skipped $SKIPPED already-existing tag(s)." diff --git a/tests/codex/test_codex_extension.py b/tests/codex/test_codex_extension.py index 95ead621..31551f0f 100644 --- a/tests/codex/test_codex_extension.py +++ b/tests/codex/test_codex_extension.py @@ -9,6 +9,19 @@ REPO_ROOT = Path(__file__).resolve().parents[2] CLAUDE_COMMANDS = REPO_ROOT / "arckit-claude" / "commands" + +# v5.0.0+: commands live across 6 plugin source directories (core + 5 +# community overlays). Mirror scripts/converter.py's PLUGIN_SOURCES list +# so this test matches the converter's actual output. +PLUGIN_COMMAND_DIRS = [ + REPO_ROOT / "arckit-claude" / "commands", + REPO_ROOT / "arckit-uae" / "commands", + REPO_ROOT / "arckit-fr" / "commands", + REPO_ROOT / "arckit-ca" / "commands", + REPO_ROOT / "arckit-eu" / "commands", + REPO_ROOT / "arckit-at" / "commands", + REPO_ROOT / "arckit-au" / "commands", +] CODEX_ROOT = REPO_ROOT / "arckit-codex" CODEX_SKILLS = CODEX_ROOT / "skills" CODEX_PROMPTS = CODEX_ROOT / "prompts" @@ -57,11 +70,15 @@ def expected_command_names() -> set[str]: - return { - path.stem - for path in CLAUDE_COMMANDS.glob("*.md") - if path.name not in CLAUDE_ONLY_COMMANDS - } + names: set[str] = set() + for cmd_dir in PLUGIN_COMMAND_DIRS: + if not cmd_dir.is_dir(): + continue + for path in cmd_dir.glob("*.md"): + if path.name in CLAUDE_ONLY_COMMANDS: + continue + names.add(path.stem) + return names def codex_skill_name(command_name: str) -> str: diff --git a/tests/paperclip/test_commands_json.py b/tests/paperclip/test_commands_json.py index 21169248..84ad4991 100644 --- a/tests/paperclip/test_commands_json.py +++ b/tests/paperclip/test_commands_json.py @@ -12,15 +12,31 @@ CLAUDE_COMMANDS_DIR = REPO_ROOT / "arckit-claude" / "commands" CLAUDE_ONLY_COMMANDS = {"build.md"} +# v5.0.0+: commands live across 6 plugin source directories. Mirror +# scripts/converter.py's PLUGIN_SOURCES list so this test matches the +# converter's actual output. +PLUGIN_COMMAND_DIRS = [ + REPO_ROOT / "arckit-claude" / "commands", + REPO_ROOT / "arckit-uae" / "commands", + REPO_ROOT / "arckit-fr" / "commands", + REPO_ROOT / "arckit-ca" / "commands", + REPO_ROOT / "arckit-eu" / "commands", + REPO_ROOT / "arckit-at" / "commands", + REPO_ROOT / "arckit-au" / "commands", +] + def expected_command_count(): - return len( - [ - path - for path in CLAUDE_COMMANDS_DIR.glob("*.md") + total = 0 + for cmd_dir in PLUGIN_COMMAND_DIRS: + if not cmd_dir.is_dir(): + continue + total += sum( + 1 + for path in cmd_dir.glob("*.md") if path.name not in CLAUDE_ONLY_COMMANDS - ] - ) + ) + return total @pytest.fixture diff --git a/tests/plugin/test_template_consistency.py b/tests/plugin/test_template_consistency.py index 227e14da..e06059f6 100644 --- a/tests/plugin/test_template_consistency.py +++ b/tests/plugin/test_template_consistency.py @@ -1,10 +1,14 @@ """ -Template consistency checks for arckit-claude/commands/*.md source files. +Template consistency checks for arckit-*/commands/*.md source files. -For every template referenced via ${CLAUDE_PLUGIN_ROOT}/templates/ in a command body, -verifies the template file exists in both: - - arckit-claude/templates/ (plugin-bundled copy) - - .arckit/templates/ (CLI-scaffolded copy) +For every template referenced via ${CLAUDE_PLUGIN_ROOT}/templates/ in a +command body, verifies the template file exists in both: + - /templates/ (plugin-bundled copy — the plugin that owns the command) + - .arckit/templates/ (CLI-scaffolded copy, merged across all plugins) + +v5.0.0+: commands live across 6 plugin source directories (core + 5 +community overlays). Each plugin's commands reference templates in its +own templates/ dir; the CLI-scaffolded copy is the union. """ import os @@ -13,22 +17,33 @@ import pytest REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) -COMMANDS_DIR = os.path.join(REPO_ROOT, "arckit-claude", "commands") -PLUGIN_TEMPLATES_DIR = os.path.join(REPO_ROOT, "arckit-claude", "templates") +PLUGIN_SOURCES = [ + "arckit-claude", + "arckit-uae", + "arckit-fr", + "arckit-ca", + "arckit-eu", + "arckit-at", + "arckit-au", +] CLI_TEMPLATES_DIR = os.path.join(REPO_ROOT, ".arckit", "templates") _TEMPLATE_RE = re.compile(r"\$\{CLAUDE_PLUGIN_ROOT\}/templates/([\w-]+\.md)") def _collect_template_refs(): - """Return list of (command_basename, template_filename) pairs.""" + """Return list of (plugin_dir, command_basename, template_filename) tuples.""" refs = [] - for path in sorted(glob.glob(os.path.join(COMMANDS_DIR, "*.md"))): - name = os.path.basename(path) - with open(path, "r", encoding="utf-8") as f: - body = f.read() - for tmpl in sorted(set(_TEMPLATE_RE.findall(body))): - refs.append((name, tmpl)) + for plugin in PLUGIN_SOURCES: + commands_dir = os.path.join(REPO_ROOT, plugin, "commands") + if not os.path.isdir(commands_dir): + continue + for path in sorted(glob.glob(os.path.join(commands_dir, "*.md"))): + name = os.path.basename(path) + with open(path, "r", encoding="utf-8") as f: + body = f.read() + for tmpl in sorted(set(_TEMPLATE_RE.findall(body))): + refs.append((plugin, name, tmpl)) return refs @@ -37,45 +52,53 @@ def _collect_template_refs(): @pytest.fixture( params=_ALL_REFS, - ids=lambda p: f"{p[0]}→{p[1]}", + ids=lambda p: f"{p[0]}/{p[1]}→{p[2]}", ) def template_ref(request): return request.param def test_template_exists_in_plugin_dir(template_ref): - """Template referenced in command must exist in arckit-claude/templates/.""" - cmd_name, tmpl = template_ref - path = os.path.join(PLUGIN_TEMPLATES_DIR, tmpl) + """Template referenced in command must exist in its own plugin's templates/.""" + plugin, cmd_name, tmpl = template_ref + path = os.path.join(REPO_ROOT, plugin, "templates", tmpl) assert os.path.isfile(path), ( - f"{cmd_name} references '{tmpl}' but it is missing from arckit-claude/templates/" + f"{plugin}/commands/{cmd_name} references '{tmpl}' but it is missing from {plugin}/templates/" ) def test_template_exists_in_cli_dir(template_ref): """Template referenced in command must exist in .arckit/templates/ (CLI copy).""" - cmd_name, tmpl = template_ref + plugin, cmd_name, tmpl = template_ref path = os.path.join(CLI_TEMPLATES_DIR, tmpl) assert os.path.isfile(path), ( - f"{cmd_name} references '{tmpl}' but it is missing from .arckit/templates/" + f"{plugin}/commands/{cmd_name} references '{tmpl}' but it is missing from .arckit/templates/" ) def test_plugin_and_cli_templates_are_in_sync(): - """Every template file in arckit-claude/templates/ must also exist in .arckit/templates/.""" - plugin_files = { - os.path.basename(p) - for p in glob.glob(os.path.join(PLUGIN_TEMPLATES_DIR, "*.md")) - } + """Every template across all 6 plugin templates/ dirs must also exist in .arckit/templates/.""" + plugin_files: set[str] = set() + for plugin in PLUGIN_SOURCES: + plugin_files.update( + os.path.basename(p) + for p in glob.glob(os.path.join(REPO_ROOT, plugin, "templates", "*.md")) + ) cli_files = { os.path.basename(p) for p in glob.glob(os.path.join(CLI_TEMPLATES_DIR, "*.md")) } - only_in_plugin = plugin_files - cli_files + only_in_plugins = plugin_files - cli_files only_in_cli = cli_files - plugin_files messages = [] - if only_in_plugin: - messages.append(f"In arckit-claude/templates/ but not .arckit/templates/: {sorted(only_in_plugin)}") + if only_in_plugins: + messages.append( + "In a plugin templates/ dir but not .arckit/templates/: " + f"{sorted(only_in_plugins)}" + ) if only_in_cli: - messages.append(f"In .arckit/templates/ but not arckit-claude/templates/: {sorted(only_in_cli)}") + messages.append( + "In .arckit/templates/ but not in any plugin templates/ dir: " + f"{sorted(only_in_cli)}" + ) assert not messages, "\n".join(messages) diff --git a/tests/plugin/v5-migration-banner.test.mjs b/tests/plugin/v5-migration-banner.test.mjs new file mode 100644 index 00000000..bb17b706 --- /dev/null +++ b/tests/plugin/v5-migration-banner.test.mjs @@ -0,0 +1,72 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { mkdtempSync, mkdirSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; + +const HOOK = resolve('arckit-claude/hooks/v5-migration-banner.mjs'); + +function runBanner(cwd) { + const result = spawnSync('node', [HOOK], { + cwd, + env: { ...process.env, CLAUDE_PROJECT_DIR: cwd }, + encoding: 'utf-8', + }); + return { stdout: result.stdout, stderr: result.stderr, status: result.status }; +} + +test('no manifest → silent', () => { + const cwd = mkdtempSync(join(tmpdir(), 'arckit-v5-')); + const r = runBanner(cwd); + assert.equal(r.stdout, ''); + assert.equal(r.status, 0); +}); + +test('manifest with UAE artefacts → suggests arckit-uae', () => { + const cwd = mkdtempSync(join(tmpdir(), 'arckit-v5-')); + mkdirSync(join(cwd, '.arckit'), { recursive: true }); + writeFileSync( + join(cwd, '.arckit/manifest.json'), + JSON.stringify({ + artefacts: [ + { command: 'arckit:uae-pdpl', path: 'projects/001-x/ARC-001-PDPL-v1.0.md' }, + { command: 'arckit:requirements', path: 'projects/001-x/ARC-001-REQ-v1.0.md' }, + ], + }), + ); + const r = runBanner(cwd); + assert.match(r.stdout, /arckit-uae/); + assert.doesNotMatch(r.stdout, /arckit-fr|arckit-ca|arckit-eu|arckit-at/); +}); + +test('ack marker present → silent', () => { + const cwd = mkdtempSync(join(tmpdir(), 'arckit-v5-')); + mkdirSync(join(cwd, '.arckit'), { recursive: true }); + writeFileSync(join(cwd, '.arckit/v5-migration-acked'), ''); + writeFileSync( + join(cwd, '.arckit/manifest.json'), + JSON.stringify({ + artefacts: [{ command: 'arckit:uae-pdpl', path: 'x' }], + }), + ); + const r = runBanner(cwd); + assert.equal(r.stdout, ''); +}); + +test('mixed jurisdictions → suggests both', () => { + const cwd = mkdtempSync(join(tmpdir(), 'arckit-v5-')); + mkdirSync(join(cwd, '.arckit'), { recursive: true }); + writeFileSync( + join(cwd, '.arckit/manifest.json'), + JSON.stringify({ + artefacts: [ + { command: 'arckit:uae-pdpl', path: 'x' }, + { command: 'arckit:fr-anssi', path: 'y' }, + ], + }), + ); + const r = runBanner(cwd); + assert.match(r.stdout, /arckit-uae/); + assert.match(r.stdout, /arckit-fr/); +});