diff --git a/.agents/skills/.gitkeep b/.agents/skills/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000..3c34ba5
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,80 @@
+name: "๐ Bug Report"
+description: Report something that is currently broken or failing in production.
+title: "[Bug] "
+labels: ["type:bug"]
+body:
+ - type: textarea
+ id: current-behavior
+ attributes:
+ label: "๐จ Current Behavior"
+ description: Clear description of what is failing right now.
+ validations:
+ required: true
+
+ - type: textarea
+ id: expected-behavior
+ attributes:
+ label: "๐ฏ Expected Behavior"
+ description: What should be happening instead?
+ validations:
+ required: true
+
+ - type: textarea
+ id: impact-if-fixed
+ attributes:
+ label: "๐ฅ End-User Impact โ if the bug is fixed"
+ description: What is the impact on the current customer if the bug is fixed?
+ placeholder: |
+ e.g., Blocked from completing checkout, visual styling issue only, data loss risk, minor workaround required
+ validations:
+ required: true
+
+ - type: textarea
+ id: impact-if-not-fixed
+ attributes:
+ label: "๐ฅ End-User Impact โ if the bug is NOT fixed"
+ description: What is the impact on the current customer if the bug is NOT fixed?
+ placeholder: |
+ e.g., Customer remains completely blocked from completing checkout, continuous risk of missing compliance audit windows, minor manual workaround remains required daily
+ validations:
+ required: true
+
+ - type: textarea
+ id: steps-to-reproduce
+ attributes:
+ label: "๐ฃ Steps to Reproduce"
+ description: Steps to reproduce the behavior.
+ placeholder: |
+ 1. Go to '...'
+ 2. Click on '....'
+ 3. Scroll down to '....'
+ 4. See error message: [Paste error log or screenshot here]
+ validations:
+ required: true
+
+ - type: input
+ id: release-version
+ attributes:
+ label: "๐ป Release Version"
+ description: Release version, or commit date if on main
+ placeholder: "[or commit date if in main]"
+ validations:
+ required: true
+
+ - type: textarea
+ id: verification-plan
+ attributes:
+ label: "๐งช Verification & Validation Plan"
+ description: How was this validated?
+ placeholder: |
+ e.g., Checked staging logs, verified with solid testing evidence, reproduced locally with automated test suite
+ validations:
+ required: true
+
+ - type: checkboxes
+ id: verification-checklist
+ attributes:
+ label: "๐งช Verification Checklist"
+ options:
+ - label: Bug patch verified successfully in target environment.
+ - label: Regression testing completed to ensure nearby features are unaffected.
diff --git a/.github/ISSUE_TEMPLATE/epic.yml b/.github/ISSUE_TEMPLATE/epic.yml
new file mode 100644
index 0000000..5cf864a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/epic.yml
@@ -0,0 +1,61 @@
+name: "๐ Epic"
+description: A parent issue that groups a set of user stories toward one outcome.
+title: "[Epic] "
+labels: ["type:epic"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ An epic is a **set of stories**, not a story itself. Size and sprint
+ the child stories. Leave this issue unpointed and off the sprint.
+ After filing, add those stories as GitHub sub-issues of this epic.
+
+ - type: textarea
+ id: outcome
+ attributes:
+ label: "๐ฏ Outcome"
+ description: What will be true when this epic is complete?
+ placeholder: One or two sentences describing the user or business outcome.
+ validations:
+ required: true
+
+ - type: textarea
+ id: why
+ attributes:
+ label: "๐ก Why this epic"
+ description: Why this work, and why now?
+ validations:
+ required: true
+
+ - type: textarea
+ id: stories
+ attributes:
+ label: "๐ Stories"
+ description: List the user stories in this epic. After this issue is created, add each as a GitHub sub-issue. Do not size this epic.
+ placeholder: |
+ - [ ] [Story] ...
+ - [ ] [Story] ...
+ - [ ] [Story] ...
+ validations:
+ required: true
+
+ - type: textarea
+ id: out-of-scope
+ attributes:
+ label: "๐ซ Out of Scope"
+ description: What is explicitly not included in this epic?
+ placeholder: |
+ - [ ] Item 1
+ - [ ] Item 2
+ validations:
+ required: false
+
+ - type: checkboxes
+ id: definition-of-done
+ attributes:
+ label: "๐ Definition of Done"
+ options:
+ - label: Child stories are filed as GitHub sub-issues of this epic.
+ - label: This epic is not sized; Size lives on the child stories.
+ - label: This epic is not assigned to a sprint; stories are.
+ - label: All child stories are complete and the outcome above is met.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 0000000..4ac0f4f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,76 @@
+name: "๐ Feature"
+description: Propose a new feature, optimization, or improvement
+title: "[Feature] "
+labels: ["type:enhancement"]
+body:
+ - type: textarea
+ id: problem-description
+ attributes:
+ label: "๐ Problem Description"
+ description: A clear and concise description of what the problem or limitation is.
+ validations:
+ required: true
+
+ - type: textarea
+ id: proposed-solution
+ attributes:
+ label: "๐ก Proposed Solution"
+ description: A clear description of what you want to happen and how this feature should look or function.
+ validations:
+ required: true
+
+ - type: textarea
+ id: benefit-if-done
+ attributes:
+ label: "๐ Current customer & Community Benefit โ if we do this"
+ description: Who benefits from this and why?
+ placeholder: |
+ e.g., Saves developers 20 minutes per day, reduces API load for self-hosted community instances, cleans up UI noise for end-users
+ validations:
+ required: true
+
+ - type: textarea
+ id: impact-if-not-done
+ attributes:
+ label: "๐ Current customer & Community Benefit โ if we DO NOT do this"
+ description: What happens to our current stakeholders if we DO NOT do this?
+ placeholder: |
+ e.g., The team will continue to accumulate manual maintenance debt, API costs will scale linearly with traffic, the user experience remains fragmented and hard to adopt for external community members
+ validations:
+ required: true
+
+ - type: textarea
+ id: validation-plan
+ attributes:
+ label: "๐งช Technical Validation & Verification Plan"
+ description: How should this feature be validated once built?
+ placeholder: |
+ e.g., Provide a script to verify structural data output, benchmark database performance, manually check responsive scaling
+ validations:
+ required: true
+
+ - type: checkboxes
+ id: validation-checklist
+ attributes:
+ label: "๐งช Verification Checklist"
+ options:
+ - label: Automated testing evidence provided (Unit or Integration tests).
+ - label: Feature verified successfully in a target staging environment.
+
+ - type: checkboxes
+ id: definition-of-done-quality
+ attributes:
+ label: "๐ Definition of Done โ ๐ ๏ธ Quality & Testing"
+ options:
+ - label: Code has been peer-reviewed for bugs and vulnerabilities.
+ - label: Proper testing has been completed and passed (Unit, Integration, E2E via GitHub Actions).
+ - label: The feature has been demonstrated/validated successfully in the target environment.
+
+ - type: checkboxes
+ id: definition-of-done-docs
+ attributes:
+ label: "๐ Definition of Done โ ๐ Architecture & Docs"
+ options:
+ - label: Usage documentation or changelog updated (if user-facing changes introduced).
+ - label: Local ADR written and verified by Architecture & Alignment Committee if technical architecture deviated.
+ - label: Any newly introduced technical debt has been logged as a GitHub Intake.
diff --git a/.github/ISSUE_TEMPLATE/spike.yml b/.github/ISSUE_TEMPLATE/spike.yml
new file mode 100644
index 0000000..0fb9f4c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/spike.yml
@@ -0,0 +1,32 @@
+name: "๐ฌ Spike"
+description: Time-boxed investigation to explore a technical approach or clear up uncertainty.
+title: "[Spike] "
+labels: ["type:spike"]
+body:
+ - type: textarea
+ id: core-question
+ attributes:
+ label: "โ The Core Question"
+ description: What specific technical unknown are we trying to answer with this exploration?
+ placeholder: |
+ Example: Can our architecture handle 500 simultaneous requests on mobile viewports?
+ validations:
+ required: true
+
+ - type: input
+ id: time-allocated
+ attributes:
+ label: "โฑ๏ธ Time Allocated"
+ description: Time-box for this spike
+ placeholder: "e.g., 4 Hours / Max 1 Day"
+ validations:
+ required: true
+
+ - type: checkboxes
+ id: required-deliverables
+ attributes:
+ label: "๐ Required Deliverables"
+ options:
+ - label: Written summary of findings added as a comment below or linked markdown file.
+ - label: Proof of Concept (PoC) code shared when applicable (branch, fork, or local investigation notes).
+ - label: Clear "Go / No-Go" technical recommendation for the Architect.
diff --git a/.github/ISSUE_TEMPLATE/task.yml b/.github/ISSUE_TEMPLATE/task.yml
new file mode 100644
index 0000000..9513117
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/task.yml
@@ -0,0 +1,32 @@
+name: "โ๏ธ Task"
+description: A technical delivery task that does not directly introduce a new user-facing feature.
+title: "[Task] "
+labels: ["type:task"]
+body:
+ - type: textarea
+ id: description
+ attributes:
+ label: "๐ Description"
+ description: Provide a clear, technical overview of what needs to be changed in the codebase.
+ validations:
+ required: true
+
+ - type: textarea
+ id: technical-checklist
+ attributes:
+ label: "๐ ๏ธ Technical Checklist"
+ description: Steps to complete this task.
+ placeholder: |
+ - [ ] Step 1 (e.g., Run database migration scripts)
+ - [ ] Step 2 (e.g., Update configuration variables in environment files)
+ - [ ] Step 3
+ validations:
+ required: true
+
+ - type: checkboxes
+ id: verification-plan
+ attributes:
+ label: "๐งช Verification Plan"
+ options:
+ - label: Peer review completed.
+ - label: All CI/CD checks pass successfully in GitHub Actions.
diff --git a/.github/ISSUE_TEMPLATE/user_story.yml b/.github/ISSUE_TEMPLATE/user_story.yml
new file mode 100644
index 0000000..5ff99ca
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/user_story.yml
@@ -0,0 +1,74 @@
+name: "๐ User Story"
+description: Describe a feature or user outcome from the user's perspective.
+title: "[Story] "
+labels: ["type:story"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ ### ๐ค User Story
+ - type: input
+ id: as-a
+ attributes:
+ label: "As a"
+ description: Type of user
+ placeholder: "[type of user]"
+ validations:
+ required: true
+ - type: input
+ id: i-want
+ attributes:
+ label: "I want to"
+ description: Perform an action / have a capability
+ placeholder: "[perform an action / have a capability]"
+ validations:
+ required: true
+ - type: input
+ id: so-that
+ attributes:
+ label: "So that"
+ description: The business value or benefit received
+ placeholder: "[the business value or benefit received]"
+ validations:
+ required: true
+
+ - type: textarea
+ id: acceptance-criteria
+ attributes:
+ label: "๐ฏ Acceptance Criteria"
+ description: What must happen for this feature to be considered structurally functional?
+ placeholder: |
+ - [ ] Criteria 1 (e.g., Clicking 'Export' generates a CSV file download)
+ - [ ] Criteria 2
+ - [ ] Criteria 3
+ validations:
+ required: true
+
+ - type: textarea
+ id: out-of-scope
+ attributes:
+ label: "๐ซ Out of Scope"
+ description: What is explicitly not included in this story?
+ placeholder: |
+ - [ ] Item 1
+ - [ ] Item 2
+ validations:
+ required: false
+
+ - type: checkboxes
+ id: definition-of-done-quality
+ attributes:
+ label: "๐ Definition of Done โ ๐ ๏ธ Quality & Testing"
+ options:
+ - label: Code has been peer-reviewed for bugs and vulnerabilities.
+ - label: Proper testing has been completed and passes (Unit, Integration, E2E via GitHub Actions).
+ - label: The feature has been demonstrated/validated successfully in the target environment.
+
+ - type: checkboxes
+ id: definition-of-done-docs
+ attributes:
+ label: "๐ Definition of Done โ ๐ Architecture & Docs"
+ options:
+ - label: Usage documentation or changelog updated (if user-facing changes introduced).
+ - label: Local ADR written and verified by Tech Lead if technical architecture deviated.
+ - label: Any newly introduced technical debt has been logged as a GitHub issue.
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 72e8f4d..5783b96 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,16 +1,24 @@
-# Dependabot configuration.
+# Dependabot configuration managed by org-infra.
+# Entries for managed ecosystems are overwritten on sync.
+# Additional ecosystem entries not managed by org-infra are preserved.
# See: https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: github-actions
- directories:
- - /
+ directory: /
schedule:
interval: daily
commit-message:
prefix: ci
include: scope
+ - package-ecosystem: pre-commit
+ directory: /
+ schedule:
+ interval: weekly
+ commit-message:
+ prefix: chore
+ include: scope
- package-ecosystem: gomod
directories:
- /
diff --git a/.github/workflows/ci_crapload.yml b/.github/workflows/ci_crapload.yml
new file mode 100644
index 0000000..9df0ac0
--- /dev/null
+++ b/.github/workflows/ci_crapload.yml
@@ -0,0 +1,102 @@
+# CRAP Load Check
+# ===============
+# Runs CRAP load analysis on pull requests targeting main.
+# Consumes the reusable workflow from org-infra.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+name: CRAP Load Check
+
+on:
+ pull_request:
+ branches:
+ - main
+
+permissions:
+ contents: read
+ pull-requests: write
+
+jobs:
+ crapload:
+ name: CRAP Load Analysis
+ uses: complytime/org-infra/.github/workflows/reusable_crapload_analysis.yml@0c784711926c9864f027ec565fd7c06a382d80f8 # v0.7.1
+ permissions:
+ contents: read
+
+ post-comment:
+ name: Post PR Comment
+ needs: crapload
+ if: ${{ !cancelled() }}
+ runs-on: ubuntu-latest
+ permissions:
+ pull-requests: write
+ steps:
+ - name: Download comment body
+ id: download
+ continue-on-error: true
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: crapload-analysis
+ path: artifact
+
+ - name: Post or update PR comment
+ continue-on-error: true
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ with:
+ script: |
+ const fs = require('fs');
+ const marker = '';
+ const bodyPath = 'artifact/crapload-comment-body.md';
+ const runUrl = [
+ context.serverUrl,
+ context.repo.owner,
+ context.repo.repo,
+ 'actions/runs',
+ context.runId,
+ ].join('/');
+ const MAX_COMMENT_LENGTH = 60000;
+
+ let body;
+ if (fs.existsSync(bodyPath)) {
+ body = fs.readFileSync(bodyPath, 'utf8');
+ if (body.length > MAX_COMMENT_LENGTH) {
+ const lastNewline = body.lastIndexOf('\n', MAX_COMMENT_LENGTH);
+ body = body.substring(0, lastNewline > 0 ? lastNewline : MAX_COMMENT_LENGTH);
+ body += '\n\n---\n';
+ body += '> **Note:** This report was truncated due to size.';
+ body += ` [View the full analysis in the Job Summary](${runUrl}).`;
+ }
+ } else {
+ body = [
+ marker,
+ '## ❌ CRAP Load Analysis',
+ '',
+ 'The CRAP Load analysis could not generate a detailed report.',
+ '',
+ `[View the full analysis in the Job Summary](${runUrl}).`,
+ ].join('\n');
+ }
+
+ const { data: comments } = await github.rest.issues.listComments({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number,
+ });
+
+ const existing = comments.find(c => c.body.includes(marker));
+
+ if (existing) {
+ await github.rest.issues.updateComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ comment_id: existing.id,
+ body,
+ });
+ } else {
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number,
+ body,
+ });
+ }
diff --git a/.github/workflows/ci_dependencies.yml b/.github/workflows/ci_dependencies.yml
index f00820f..876eb00 100644
--- a/.github/workflows/ci_dependencies.yml
+++ b/.github/workflows/ci_dependencies.yml
@@ -1,5 +1,13 @@
name: Dependencies
+# --------------------------------------------------------------------------
+# Orchestrates dependency review for all PRs and dependabot-specific
+# processing: structured PR comments with review data and auto-approval
+# for safe dependency updates (non-major, 24h+ release age, no vulnerabilities).
+# Org-owned dependencies (same GitHub org) skip the release age gate and
+# get auto-merge enabled for patch/minor updates.
+# --------------------------------------------------------------------------
+
on:
push:
branches:
@@ -32,7 +40,7 @@ jobs:
needs: [call_deps_reviewer, call_dependabot_reviewer]
permissions:
issues: read
- pull-requests: write
+ pull-requests: write # Necessary to write a comment
steps:
- name: Comment from Dependabot Reviewer
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
@@ -77,8 +85,8 @@ jobs:
runs-on: ubuntu-latest
needs: [call_deps_reviewer, call_dependabot_reviewer]
permissions:
- contents: write
- pull-requests: write
+ contents: write # Required for gh pr merge --auto
+ pull-requests: write # Required to approve a PR
steps:
- name: Auto-approve if Confident
id: auto_approve
diff --git a/.github/workflows/ci_scheduled.yml b/.github/workflows/ci_scheduled.yml
index a7c96a2..e84b7ec 100644
--- a/.github/workflows/ci_scheduled.yml
+++ b/.github/workflows/ci_scheduled.yml
@@ -2,7 +2,7 @@ name: Scheduled Jobs
on:
schedule:
- - cron: '0 0 * * *'
+ - cron: "0 0 * * *"
permissions:
contents: read
@@ -15,7 +15,7 @@ jobs:
name: OSV-Scanner and Scorecards
permissions:
contents: read
- actions: read
- security-events: write
- id-token: write
+ actions: read # Required to upload SARIF file to CodeQL. See: https://github.com/github/codeql-action/issues/2117
+ security-events: write # Require writing security events to upload SARIF file to security tab
+ id-token: write # Needed to access GitHub's OIDC token which verifies the authenticity of the result when publishing it.
uses: complytime/org-infra/.github/workflows/reusable_scheduled.yml@0c784711926c9864f027ec565fd7c06a382d80f8 # v0.7.1
diff --git a/.github/workflows/ci_security.yml b/.github/workflows/ci_security.yml
index fc79d78..b771491 100644
--- a/.github/workflows/ci_security.yml
+++ b/.github/workflows/ci_security.yml
@@ -24,7 +24,9 @@ jobs:
security-events: write
uses: complytime/org-infra/.github/workflows/reusable_vuln_scan.yml@0c784711926c9864f027ec565fd7c06a382d80f8 # v0.7.1
with:
- enable_trivy_source: true
+ # OSV focuses on known CVEs in dependencies; Trivy adds broader coverage
+ enable_trivy_source: false
+ trivy_ignorefile: ''
call_reusable_security:
name: OpenSSF Scorecards
diff --git a/.golangci.yml b/.golangci.yml
index 33ebf81..06716f8 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -1,9 +1,8 @@
-# SPDX-License-Identifier: Apache-2.0
version: "2"
linters:
- default: standard
+ default: standard # https://golangci-lint.run/usage/linters/#enabled-by-default
enable:
- - gosec
+ - gosec # Security checks for Go code
exclusions:
generated: lax
presets:
@@ -13,6 +12,6 @@ linters:
- std-error-handling
formatters:
enable:
- - goimports
+ - goimports # Checks import statements are formatted
exclusions:
generated: lax
diff --git a/.mega-linter.yml b/.mega-linter.yml
index ddcdd90..82d6f51 100644
--- a/.mega-linter.yml
+++ b/.mega-linter.yml
@@ -1,12 +1,25 @@
-# SPDX-License-Identifier: Apache-2.0
# https://megalinter.io/latest/supported-linters/
+# .opencode and .claude contain AI agent/skill definitions with intentional
+# formatting patterns that conflict with markdownlint and yamllint rules.
+# Other scanners (grype, Trivy, OSV-Scanner, REPOSITORY_BETTERLEAKS) still
+# cover these paths -- only MegaLinter's style linters are excluded.
+ADDITIONAL_EXCLUDED_DIRECTORIES:
+ - vendor
+ - .opencode
+ - .claude
+MARKDOWN_MARKDOWNLINT_FILTER_REGEX_EXCLUDE: "(vendor/)"
+PROTOBUF_PROTOLINT_FILTER_REGEX_EXCLUDE: "(vendor/)"
ENABLE_LINTERS:
- ACTION_ZIZMOR
- ACTION_ACTIONLINT
+ - ANSIBLE_ANSIBLE_LINT
- BASH_SHELLCHECK
+ - DOCKERFILE_HADOLINT
- GO_GOLANGCI_LINT
- MARKDOWN_MARKDOWNLINT
+ - PYTHON_RUFF
+ - PROTOBUF_PROTOLINT
- REPOSITORY_BETTERLEAKS
+ - REPOSITORY_KICS
- YAML_YAMLLINT
-ACTION_ZIZMOR_UNSECURED_ENV_VARIABLES:
- - GITHUB_TOKEN
+REPOSITORY_KICS_ARGUMENTS: "--fail-on high"
diff --git a/.opencode/commands/review-pr.md b/.opencode/commands/review-pr.md
index a524581..991bed9 100644
--- a/.opencode/commands/review-pr.md
+++ b/.opencode/commands/review-pr.md
@@ -1,7 +1,7 @@
---
description: "Review a pull request for alignment, security, and constitution compliance"
---
-
+
# Review Pull Request
@@ -28,7 +28,7 @@ which gh
```
If `gh` is not found: **STOP** with error:
-> "`gh` CLI is not installed. Install it from https://cli.github.com/ or via your package manager."
+> "`gh` CLI is not installed. Install it from or via your package manager."
If `gh` is found, verify authentication:
@@ -89,10 +89,10 @@ If no open PR exists for the current branch: **STOP** with error:
Retrieve PR metadata first โ avoid loading the full diff until needed:
```bash
-gh pr view --json title,body,files,additions,deletions,baseRefName,headRefName,labels,milestone,commits,reviewDecision,reviewRequests
+gh pr view --json title,body,files,additions,deletions,baseRefName,headRefName,labels,milestone,commits
```
-Record the PR title, description, branch name, base branch, changed file list, current review decision (`REVIEW_REQUIRED`, `APPROVED`, `CHANGES_REQUESTED`), and pending review requests. **Do NOT fetch the full diff yet** โ later steps determine which files need AI analysis.
+Record the PR title, description, branch name, base branch, and changed file list. **Do NOT fetch the full diff yet** โ later steps determine which files need AI analysis.
### 3. Fetch CI Check Results
@@ -133,7 +133,7 @@ gh api repos/{owner}/{repo}/commits/${BASE_BRANCH}/check-runs \
**Classification**:
| Base branch status | PR check status | Classification |
-|--------------------|-----------------|----------------|
+| -------------------- | ----------------- | ---------------- |
| Pass | Fail | **PR-caused** โ the PR introduced the failure |
| Fail | Fail | **Pre-existing** โ failure exists independently of the PR |
| No data | Fail | **Unknown** โ treat as PR-caused (conservative) |
@@ -162,7 +162,7 @@ that covers the same verification. Display this matrix
to make the skip/run decision visible:
| Local tool | CI check that covers it | CI status | Run locally? |
-|------------|------------------------|-----------|--------------|
+| ------------ | ------------------------ | ----------- | -------------- |
| `go test` | e.g., "Local CI / test" | PASS/FAIL/NONE | Yes/No |
| `golangci-lint` | e.g., "CI Checks / lint" | PASS/FAIL/NONE | Yes/No |
| ... | ... | ... | ... |
@@ -181,7 +181,7 @@ Decision rules:
matrix above:
| Tool detected | Command to run | What it checks |
-|---------------|----------------|----------------|
+| --------------- | ---------------- | ---------------- |
| Makefile | `make lint` (or `make check`) | Project-defined lint/format/vet |
| `.golangci.yml` | `golangci-lint run ./...` | Go lint rules |
| `ruff.toml` / `pyproject.toml` | `ruff check .` | Python lint rules |
@@ -355,88 +355,10 @@ Use pack rules (CS-001, AP-001, SC-001, TC-001, DR-001, etc.) alongside the cons
**If packs are NOT available**: proceed without them. Use the constitution and inline severity definitions only. No error or warning needed.
-### 7.5. Fetch Existing Review State
-
-Fetch existing PR reviews and inline comments to prevent
-duplicate findings and provide context for the AI review.
-
-#### 7.5a. Fetch Reviews
-
-```bash
-gh api repos/{owner}/{repo}/pulls//reviews \
- --jq '[.[] | {id: .id, user: .user.login, state: .state, body: .body, submitted_at: .submitted_at, commit_id: .commit_id}]'
-```
-
-Record each review's user, state (`APPROVED`,
-`CHANGES_REQUESTED`, `COMMENTED`, `DISMISSED`), body,
-and commit ID.
-
-#### 7.5b. Fetch Inline Comments
-
-```bash
-gh api repos/{owner}/{repo}/pulls//comments \
- --jq '[.[] | {path: .path, line: .line, body: .body, user: .user.login, created_at: .created_at}]'
-```
-
-Record each inline comment's file path, line number,
-body, and author.
-
-#### 7.5c. Identify Current User
-
-```bash
-gh api user --jq '.login'
-```
-
-Record the authenticated user's login for duplicate
-review detection in Step 11.
-
-#### 7.5d. Token Budget
-
-Existing review comments passed to Step 8 MUST be capped
-at 3000 characters total to prevent token bloat. When the
-combined comment text exceeds this limit:
-1. Filter to comments on files changed in this PR
-2. Sort by `created_at` descending (most recent first)
-3. Include comments until the 3000-character budget is
- exhausted
-4. Truncate the remainder with a note: "N additional
- prior comments truncated for token budget"
-
-#### 7.5e. Error Handling
-
-If any `gh api` call in this step returns 403, 404, or
-times out:
-- Log the error
-- Skip the failed sub-step
-- Proceed to Step 8 without the missing context
-
-The review continues without blocking. All review state
-data is additive context โ its absence does not reduce
-the review's capability, only its deduplication accuracy.
-
### 8. AI Review (Judgment-Based Only)
Focus AI analysis exclusively on what deterministic tools and CI cannot check. Skip any category where local tools or CI already passed.
-**Existing review deduplication** (using Step 7.5 data):
-Before generating findings, cross-reference existing
-inline comments from Step 7.5b against the current
-analysis. For each finding:
-- If an existing inline comment covers the same file and
- line range with a similar concern: **annotate** the
- finding as "previously raised by @user" rather than
- presenting it as new. Include the annotation in the
- output.
-- If an existing review thread appears resolved (the
- author pushed fixes after the comment): **acknowledge**
- this in the finding context.
-- If prior reviewer discussions provide relevant context
- for a finding: **reference** them (e.g., "Related to
- @user's comment on the same file").
-- Do NOT fully suppress findings โ the current review may
- have additional context or a different severity
- assessment. Annotate, don't hide.
-
**Path-based review focus**: Before starting the review,
classify each changed file against these built-in
heuristics. Record the focus category for each file
@@ -444,7 +366,7 @@ heuristics. Record the focus category for each file
context):
| Path pattern | Focus category | Additional emphasis |
-|-------------|---------------|-------------------|
+| ------------- | --------------- | ------------------- |
| `*_test.go`, `*_test.py`, `**/__tests__/**`, `**/*_spec.*` | `test-quality` | Edge cases, assertion strength, mock isolation, test naming |
| `**/cmd/**`, `**/cli/**` | `cli-ux` | Error messages, flag validation, help text |
| `**/api/**`, `**/handler/**`, `**/middleware/**`, `**/routes/**` | `security` | Auth, input validation, injection |
@@ -706,72 +628,6 @@ before posting anything.
**If the user agrees**:
-#### 11a. Pre-posting Checks
-
-Before preparing comments, run three state-awareness
-checks using data from Step 7.5:
-
-**Duplicate review detection**: Check if a review from
-the current user (Step 7.5c) already exists in the
-review list (Step 7.5a):
-
-- If a prior review with the **same verdict** exists:
- ```
- You already have an review
- on this PR. Post a new one? (The latest review takes
- precedence.)
- (yes/no)
- ```
-- If a prior review with a **different verdict** exists:
- ```
- You have a prior review. Post a new
- ? This will override the previous
- verdict.
- (yes/no)
- ```
-- If no prior review exists: proceed silently.
-
-**Stale review + CODEOWNER checks** (APPROVE verdicts
-only): Fetch branch protection settings in a single API
-call to avoid redundant requests:
-
-```bash
-gh api repos/{owner}/{repo}/branches//protection \
- --jq '{dismiss_stale: .required_pull_request_reviews.dismiss_stale_reviews, require_codeowners: .required_pull_request_reviews.require_code_owner_reviews}'
-```
-
-If the API returns 404 (no branch protection) or 403
-(insufficient permissions): skip both checks silently.
-
-If `dismiss_stale` is true, display:
-```
-Warning: This repo dismisses stale reviews. If the author
-pushes any new commits after this APPROVE, it will be
-automatically invalidated and the PR will return to
-REVIEW_REQUIRED. You may need to re-run /review-pr after
-final commits.
-```
-
-If `require_codeowners` is true, check for CODEOWNERS
-file:
-
-```bash
-gh api repos/{owner}/{repo}/contents/CODEOWNERS \
- --jq '.name' 2>/dev/null || \
-gh api repos/{owner}/{repo}/contents/.github/CODEOWNERS \
- --jq '.name' 2>/dev/null
-```
-
-If CODEOWNERS exists and `require_code_owner_reviews` is
-true, display:
-```
-Warning: This repo requires code owner reviews. This
-APPROVE may not satisfy branch protection if this
-account is not listed in CODEOWNERS.
-```
-
-If any API call fails: skip silently.
-
1. **Prepare comments**: For each finding that maps to a
specific file and line range in the diff, prepare an
in-line comment with:
diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md
new file mode 100644
index 0000000..8442a88
--- /dev/null
+++ b/.specify/memory/constitution.md
@@ -0,0 +1,271 @@
+
+
+# ComplyTime Constitution
+
+## Core Principles
+
+### I. Single Source of Truth (Centralized Constants)
+
+Values used in multiple places or that may change over time MUST be centralized. Magic strings (e.g., `"active"`, `"https://api..."`) and magic numbers (e.g., `86400`) MUST NOT appear inline within logic. These values MUST be moved into dedicated files (e.g., `internal/consts/consts.go`, `settings.py`).
+
+**Rationale**: Prevents divergence -- updating a timeout from 30s to 60s in one file ensures every part of the application updates automatically. Avoids "shotgun surgery" -- a single logical change MUST NOT require search-and-replace across multiple files, reducing the risk of missed instances and introduced bugs.
+
+### II. Simplicity & Isolation
+
+Code MUST reduce complexity to improve security and maintainability. Functions MUST follow the Single Responsibility Principle -- small, focused, and independently testable. Prefer isolated, composable parts over monolithic and inflexible approaches.
+
+**Rationale**: Small, isolated components reduce cognitive load, improve testability, and minimize the blast radius of changes.
+
+### III. Incremental Improvement
+
+Improvements to existing code are welcome, but each contribution MUST remain focused on a single concern. Changes unrelated to the current task (refactoring, formatting fixes, better naming) MUST be proposed in a separate commit or Pull Request. Before including incidental improvements, assess their impact on other core principles and justify the scope expansion.
+
+**Rationale**: Keeping aesthetic changes separate from logic fixes ensures that PRs remain atomic and easier to review.
+
+### IV. Readability First
+
+Code is read far more often than it is written. All code MUST prioritize clarity for the reader over brevity or convenience for the writer.
+
+**Implementation**:
+- **Explicit Naming**: Variable and function names MUST clearly describe their intent (e.g., use `days_until_expiration` instead of `d`).
+- **Avoid "Clever" Code**: MUST NOT use complex one-liners or obscure language features that require deep mental parsing. If the implementation is hard to explain, it is a bad implementation.
+- **Self-Documenting**: The code structure itself MUST explain the logic. Comments MUST explain the *why* (business logic/intent), not the *what* (syntax).
+
+**Rationale**: Readable code reduces onboarding time, prevents bugs from misunderstanding, and enables faster debugging.
+
+### V. Do Not Reinvent the Wheel
+
+Leverage existing solutions and validate their quality.
+
+**Implementation**:
+- **Prefer Established Libraries**: MUST NOT introduce custom implementations when a well-established, actively maintained library or cloud-native solution exists for the same purpose.
+- **Vet Dependencies**: New dependencies MUST be actively maintained (recent release activity) and have a clear governance model. SHOULD NOT adopt abandoned or single-maintainer projects for critical functionality.
+- **No Hard Forks**: MUST NOT create hard forks or permanent local workarounds for upstream libraries. If upstream changes are needed, they SHOULD be contributed back in a separate effort.
+
+**Rationale**: Using well-maintained libraries reduces maintenance burden. Contributing back improves the ecosystem and reduces the technical debt of maintaining internal patches.
+
+### VI. Composability (The Unix Philosophy)
+
+Programs and functions MUST do one thing and do it well. Programs and functions MUST be designed to work together. All tools MUST be modular. Output from one tool MUST be easily consumable as input for another (e.g., standard JSON/YAML streams).
+
+**Rationale**: Modular tools enable composition, reuse, and integration with external systems. Standard formats ensure interoperability.
+
+### VII. Convention Over Configuration
+
+Decrease the number of decisions a developer or user needs to make. Provide defaults aligned with the most common use case. Users SHOULD only need to specify configuration when deviating from the established standard.
+
+**Rationale**: Reduces cognitive load, accelerates onboarding, and prevents configuration errors through well-chosen defaults.
+
+## Repository Structure & Standards
+
+Every repository under the ComplyTime organization MUST contain the following standard files in the root directory to ensure a consistent developer experience:
+
+| File | Description | Standard |
+| :--- | :---- | :---- |
+| `README.md` | Project overview, installation, and usage. | Markdown |
+| `LICENSE` | Legal terms of use. | **Apache License 2.0** |
+| `CONTRIBUTING.md` | Guidelines for contributors. | Link to org-wide guide or repo-specific details. |
+| `CODE_OF_CONDUCT.md` | Community standards. | Standard Contributor Covenant |
+| `SECURITY.md` | Security policy. | Vulnerability reporting instructions |
+| `.github/` | GitHub configuration. | Issue templates, PR templates, workflows. |
+
+These files MUST link to org-wide definitions whenever available and MAY be incremented with repository-specific content.
+
+## Contribution Workflow
+
+### Branching Strategy
+
+- **Main Branch**: `main` is the stable production branch.
+- **Feature Branches**: All changes MUST be developed on branches created from `main`.
+
+### Pull Requests (PRs)
+
+- **Atomic Changes**: PRs MUST address a single concern and be small enough for focused review. Large, multi-concern PRs SHOULD be split into separate submissions.
+- **Review Requirement**: All PRs REQUIRE review from at least two Maintainers.
+- **CI/CD Gates**:
+ - **Standard**: All PRs MUST generally pass automated checks (linting, testing, build) before merging.
+ - **Exceptions**: Checks MAY occasionally fail due to external issues or transient flakes. In these rare instances, maintainers MAY agree on exceptions to merge specific PRs despite a failing status.
+- **Pull Request Title Format**: `: ` (e.g., `feat: implement oscal validation logic`)
+
+### Commit Messages
+
+All commit messages MUST follow the **Conventional Commits** [specification](https://www.conventionalcommits.org/).
+
+### Commit Trailers
+
+- **Signed-off-by**: All commits MUST include a `Signed-off-by` trailer with the author's name and email (use `git commit -s`). This certifies the contributor's right to submit the code under the project's license ([Developer Certificate of Origin](https://developercertificate.org/)).
+- **Assisted-by**: Commits that were authored or substantially assisted by an AI tool MUST include an `Assisted-by` trailer identifying the tool and model (e.g., `Assisted-by: OpenCode (claude-opus-4-6)`). This ensures transparency and traceability of AI-assisted contributions.
+
+## Infrastructure Standards Centralization
+
+Workflows, configurations, and templates SHOULD be centralized in the [org-infra](https://github.com/complytime/org-infra) repository, which serves as the canonical source for organization-wide CI/CD standards. Repository-specific overrides MAY exist but MUST NOT conflict with centralized definitions. Changes to shared infrastructure MUST be proposed in org-infra first.
+
+## Coding Standards
+
+### Guidelines for All Programming Languages
+
+- **Empty Line at End of File**: All files MUST end with a single empty line. This ensures clean version control diffs and adheres to POSIX standards.
+- **Pre-commit Hooks**: Repositories SHOULD configure pre-commit and pre-push hooks via [pre-commit](https://pre-commit.com/).
+- **Makefile**: Repositories MUST use a Makefile to centralize code-specific commands.
+- **Testing**: All code MUST have tests. Test functions MUST use descriptive names and include edge cases. Inputs from external sources MUST be tested. Each test scenario MUST include at least one positive and one negative test case to verify that errors and exceptions are properly handled.
+- **Line Length**: Lines in source code MUST be limited to 99 characters unless exceeding the limit demonstrably improves readability. YAML files are exempt and follow the `.yamllint.yml` configuration instead.
+- **Lint**: Code MUST have zero lint issues according to the lint configuration defined in the repository. No trailing spaces.
+- **Lint Configuration Awareness**: Before making code changes, agents MUST read the repository's lint and formatter configuration files to understand the enforced rules. All generated or modified code MUST conform to these configurations. If no lint configuration is present, agents SHOULD follow the language-specific defaults defined in this constitution. The ComplyTime organization standardizes on the following configuration files:
+ - `.golangci.yml` -- Go linting rules
+ - `ruff.toml` or `pyproject.toml` `[tool.ruff]` -- Python linting rules
+ - `.mega-linter.yml` -- Multi-language linting in CI
+ - `.pre-commit-config.yaml` -- Pre-commit and pre-push hook definitions
+ - `.yamllint.yml` -- YAML linting rules
+
+**Note**: The following language-specific sections apply to repositories containing source code in the respective language. Repositories that host configuration files as sync templates (e.g., `.golangci.yml` in org-infra) are not subject to these sections for their own code.
+
+### Go
+
+#### General Guidelines
+
+- **File Naming**: File names MUST use lowercase letters and underscores (e.g., `my_file.go`).
+- **Package Names**: Package names MUST be short, concise, and lowercase. MUST NOT use underscores or mixed caps.
+- **Error Handling**: Errors MUST always be checked and handled appropriately. Errors SHOULD be returned to the caller when the current function cannot resolve them.
+
+#### Licensing and File Headers
+
+```go
+// SPDX-License-Identifier: Apache-2.0
+```
+
+#### Code Formatting
+
+Formatting SHOULD be aligned with native go format tools, [`goimports`](https://pkg.go.dev/golang.org/x/tools/cmd/goimports) and [`go fmt`](https://go.dev/blog/gofmt).
+
+#### Additional Guidelines
+
+Repositories SHOULD define Go-specific lint rules (e.g., via `.golangci.yml`) and run them in CI/CD. These checks SHOULD also be run locally before submitting a PR.
+
+### Python
+
+#### General Guidelines
+
+- **Type Hinting**: All Python code MUST use type hints to improve readability and tooling support.
+
+#### Licensing and File Headers
+
+```python
+# SPDX-License-Identifier: Apache-2.0
+```
+
+#### Code Formatting
+
+- **Style**: Code MUST be formatted with `black` and `isort`, or equivalently with `ruff format` and `ruff check --select I`.
+- **Lint**: Code MUST pass `ruff` linting.
+- **Static type check**: Code SHOULD pass `mypy` static type checking. Repositories with minimal scripting (e.g., a single utility script) MAY omit `mypy` if type hints are present.
+- **Non-Python files**: SHOULD use [Megalinter](https://github.com/oxsecurity/megalinter) or equivalent to lint non-Python files in a CI task. Repository-specific configuration details belong in each repository's own constitution increment.
+
+### YAML / GitHub Actions Workflows
+
+#### Naming Conventions
+
+- **Reusable workflows**: MUST be prefixed with `reusable_` and have a clear, descriptive name reflecting their function (e.g., `reusable_vuln_scan.yml`).
+- **Consumer workflows**: Workflows that call reusable workflows MUST be prefixed with `ci_` (e.g., `ci_security.yml`).
+- **Org-infra-only workflows**: Workflows that run only in `org-infra` (not synced to consumer repos, not `workflow_call`) SHOULD use a verb prefix such as `sync_` or `report_` rather than `ci_` or `reusable_` (e.g., `sync_labels.yml`, `sync_project_board.yml`, `report_sprint_velocity.yml`).
+
+#### Security
+
+- Workflows MUST follow the **Principle of Least Privilege**. Write permissions MUST be avoided; when necessary, they MUST be defined in the minimal possible scope.
+- Prefer defining explicit `permissions` per Job over workflow-level permissions.
+- Secrets MUST NOT be hardcoded in workflow files. Use GitHub Secrets or environment-based injection.
+
+#### Design
+
+- Reusable workflows MUST be generic enough to be consumed by any repository within the organization.
+- Workflow inputs MUST have descriptive `description` fields.
+- Required inputs MUST be marked with `required: true`.
+- Optional inputs SHOULD provide sensible `default` values.
+
+#### Formatting
+
+- YAML files MUST be linted with `yamllint` using the repository's `.yamllint.yml` configuration.
+- YAML line length is governed by the `.yamllint.yml` configuration and is exempt from the 99-character general rule.
+- Workflow files MUST include a header comment block describing the workflow's purpose.
+
+### Containers
+
+#### Image Building
+
+- Container images MUST be built using the org-infra reusable workflow (`reusable_publish_ghcr.yml`) or an equivalent workflow that produces the same supply chain artifacts.
+- Containerfiles MUST use a specific base image tag or digest. MUST NOT use `latest` or floating tags.
+- Multi-stage builds SHOULD be used to minimize final image size and attack surface.
+
+#### Supply Chain Security
+
+- All container images MUST include the following attestations:
+ - **SLSA provenance**: Generated during the build process.
+ - **SBOM**: Software Bill of Materials attached to the image.
+ - **Vulnerability scan**: Scan results attested to the image.
+- All attestations MUST be signed using Sigstore keyless signing with Rekor transparency log entries.
+- Signature verification MUST validate certificate identity and OIDC issuer.
+
+#### Registry Standards
+
+- Primary registry: GitHub Container Registry (`ghcr.io`).
+- Promotion to secondary registries (e.g., Quay.io) MUST verify source image signatures before copying.
+- OCI labels (`org.opencontainers.image.*`) SHOULD be applied for description, vendor, source, and version metadata.
+
+## Governance
+
+This constitution supersedes all other practices and serves as the central source of truth for engineering standards, contribution workflows, and architectural principles for the ComplyTime organization. All contributors, maintainers, and code agents MUST adhere to these guidelines to ensure consistency, quality, and compliance.
+
+### Amendment Procedure
+
+- Amendments REQUIRE documentation of the rationale and impact assessment.
+- Amendments MUST be reviewed by at least two Maintainers.
+- Version MUST increment according to semantic versioning:
+ - **MAJOR**: Backward incompatible governance/principle removals or redefinitions.
+ - **MINOR**: New principle/section added or materially expanded guidance.
+ - **PATCH**: Clarifications, wording, typo fixes, non-semantic refinements.
+
+### Compliance Review
+
+- All PRs/reviews MUST verify compliance with this constitution.
+- Complexity MUST be justified when deviating from principles.
+- This constitution MUST be used as the authoritative reference for runtime development guidance and decision-making.
+
+### Incrementing This Constitution
+
+This constitution is the org-wide shared reference for all ComplyTime repositories, maintained canonically in the `org-infra` repository.
+
+**For org-infra maintainers**: Changes to this file follow the Amendment Procedure above.
+
+**For all other repositories**: Individual repositories MUST NOT modify the org-wide constitution file. Instead, each repository SHOULD create its own `.specify/memory/constitution.md` that:
+
+1. References this org-wide constitution as its base authority.
+2. Adds repository-specific standards (e.g., additional lint rules, architecture constraints, technology-specific conventions) that do not conflict with the principles defined here.
+3. MAY tighten org-wide SHOULD directives to MUST for that repository's context, but MUST NOT relax org-wide MUST directives.
+
+Repository-level constitutions are incremental -- they extend, not replace, this document. In case of conflict, this org-wide constitution takes precedence.
+
+**Version**: 1.3.0 | **Ratified**: 2026-02-25 | **Last Amended**: 2026-08-27
diff --git a/.yamllint.yml b/.yamllint.yml
index 70cfb43..74b8af2 100644
--- a/.yamllint.yml
+++ b/.yamllint.yml
@@ -1,6 +1,7 @@
---
extends: default
+# https://yamllint.readthedocs.io/en/stable/rules.html
rules:
comments: disable
document-start: disable
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000..7157d04
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,20 @@
+# Security Policy
+
+## Reporting a Vulnerability
+
+To report a security vulnerability, either:
+
+1. **GitHub Private Vulnerability Reporting** (preferred): Navigate to the
+ Security tab on the affected repository, click "Advisories", then
+ "Report a vulnerability". See the
+ [GitHub guide](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability)
+ for details.
+
+2. **Email**: Send a report to `complytime-security@redhat.com` with a
+ description of the issue and the affected project(s).
+
+Do NOT open a public GitHub issue for security vulnerabilities.
+
+For the full organization-wide security policy, including what to include
+in a report, public disclosure process, and supported versions, see the
+[ComplyTime Security Policy](https://github.com/complytime/community/blob/main/SECURITY.md).
diff --git a/commitlint.config.js b/commitlint.config.js
index 84abd7a..ddf41a3 100644
--- a/commitlint.config.js
+++ b/commitlint.config.js
@@ -1,4 +1,3 @@
-// SPDX-License-Identifier: Apache-2.0
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
diff --git a/docs/AI_TOOLING.md b/docs/AI_TOOLING.md
new file mode 100644
index 0000000..3502ae0
--- /dev/null
+++ b/docs/AI_TOOLING.md
@@ -0,0 +1,140 @@
+# AI Tooling
+
+This repository uses AI tools to help contributors code, review PRs, and manage feature specifications. [OpenCode](https://opencode.ai) is the standardized agent tool. [OpenSpec](https://opencode.ai) is the recommended spec-driven framework โ both OpenSpec and SpecKit are agent-agnostic and work with any supported AI tool.
+
+## Getting Started
+
+### OpenCode (Recommended)
+
+```bash
+git clone
+cd
+opencode .
+```
+
+OpenCode auto-discovers project-specific commands from `.opencode/commands/`. Install the OpenSpec or SpecKit plugin to get framework commands (like `/speckit.specify`).
+
+### Other AI Tools
+
+Any AI agent that supports command loading can use this repository's AI tooling:
+
+1. Clone the repository
+2. Install OpenSpec or SpecKit for your AI agent
+3. Read `.specify/memory/constitution.md` for coding standards
+4. Reference `.opencode/commands/` for project-specific command definitions
+
+## Commands
+
+### `/review-pr `
+
+Reviews a pull request for alignment, security, and compliance. Designed to be token-efficient and CI-aware.
+
+```
+/review-pr 42
+```
+
+**How it works:**
+1. **Checks CI status** โ fetches check suite results and triages failures: distinguishes PR-caused failures from pre-existing issues on the base branch.
+2. **Runs local tools** โ detects and executes linters, test runners, and formatters available in the project (per `.specify/memory/constitution.md` Coding Standards). Skips checks CI already covered.
+3. **AI reviews what tools can't** โ focuses on intent alignment, security patterns, and architectural concerns.
+4. **Offers fix-branch for pre-existing CI failures** โ if a CI failure exists independently of the PR, offers to create a fix branch with a proposed resolution. You review and file the PR when ready.
+5. **Offers in-line PR comments** โ for HIGH+ findings, prepares in-line comments and shows them to you for confirmation before posting to the PR.
+
+**What it checks:**
+- CI: check suite pass/fail with causality triage (PR-caused vs. pre-existing)
+- Local tools: lint, formatting, tests, coverage (deterministic, zero AI tokens)
+- AI: alignment between PR intent/spec and code, security vulnerabilities, constitution compliance (judgment-based)
+
+**Output:** CI status table + local tool results + structured AI findings with severity levels (CRITICAL / HIGH / MEDIUM / LOW), verdict, optional fix-branch for pre-existing failures, and optional in-line PR comments.
+
+## Creating Commands
+
+Commands are action-oriented prompts that the agent executes when invoked. They go in `.opencode/commands/`. Framework commands (speckit.\*, opsx-\*) are managed by the plugin and should not be committed.
+
+### File structure
+
+1. Create `.opencode/commands/your-command.md`
+2. Add YAML frontmatter:
+ ```yaml
+ ---
+ description: "Brief description of what the command does"
+ ---
+ ```
+3. Write the command instructions in Markdown
+4. Submit a PR
+
+### Writing effective commands
+
+- **Single purpose**: One command = one job. Combine concerns by chaining commands, not by overloading one.
+- **Set the role first**: Open with a one-sentence persona and goal (e.g., "You are a token-efficient code reviewer."). This anchors the agent's behavior.
+- **Define arguments**: List required and optional inputs with examples so the agent knows what to expect from the user.
+- **Use numbered steps**: Break the workflow into sequential steps the agent follows. Each step should have a clear action and expected output.
+- **Delegate to tools first**: If a check can be done deterministically (lint, test, format), run the tool and use its output โ don't spend AI tokens re-analyzing what a tool already covers.
+- **Specify the output format**: Define the exact structure of the response (headings, tables, severity levels). This keeps output consistent across runs and reviewers.
+- **Reference, don't inline**: Point to `.specify/memory/constitution.md` for standards instead of copying rules into the command. This avoids drift and saves tokens.
+
+See `.opencode/commands/review-pr.md` as a reference implementation.
+
+## Creating Skills
+
+Skills provide domain knowledge the agent loads as context when activated. Unlike commands (which define *what to do*), skills define *how to think* about a specific domain. No skills are shipped initially โ the structure is ready for contributors to add them.
+
+### File structure
+
+1. Create a directory: `.agents/skills/your-skill-name/`
+2. Add a `SKILL.md` with YAML frontmatter:
+ ```yaml
+ ---
+ name: your-skill-name
+ description: "What this skill does"
+ license: MIT
+ compatibility: opencode
+ metadata:
+ audience: contributors
+ ---
+ ```
+3. Write the skill instructions in Markdown below the frontmatter
+4. Submit a PR
+
+### Writing effective skills
+
+- **Domain, not workflow**: A skill teaches the agent *about* a subject (e.g., "OSCAL compliance requirements," "Go error handling patterns"). For step-by-step workflows, create a command instead.
+- **Keep it short**: Skills are loaded into context on activation, consuming tokens for the entire session. Target under 200 lines. If it's longer, split into focused sub-skills.
+- **Be prescriptive**: State rules as "MUST / MUST NOT / SHOULD" directives the agent can follow mechanically. Avoid vague guidance like "consider security best practices."
+- **Include examples**: Show 1-2 concrete before/after examples of correct vs. incorrect patterns. Examples anchor understanding better than abstract rules.
+- **Reference external docs**: Link to detailed specifications or standards rather than inlining them. The agent can fetch them when needed instead of carrying them in context permanently.
+
+## Key Files
+
+| File | Purpose |
+|-----------------------------------|-----------------------------------------------------------------------|
+| `.specify/memory/constitution.md` | Organizational governance and coding standards |
+| `docs/AI_TOOLING.md` | This file โ AI tooling documentation |
+| `.agents/skills/` | Directory for AI skills โ agent-agnostic, auto-discovered by OpenCode |
+| `.opencode/commands/review-pr.md` | PR review command |
+| `specs/` | Feature specifications โ SpecKit output |
+| `openspec/` | Feature specifications โ OpenSpec output |
+
+## Specifications
+
+Features are managed via spec-driven development. SpecKit and OpenSpec use separate output directories with coordinated sequential numbering:
+
+```
+specs/ # SpecKit output
+โโโ 001-first-feature/
+โ โโโ spec.md
+โโโ 002-second-feature/
+โ โโโ spec.md
+โโโ ...
+
+openspec/ # OpenSpec output
+โโโ 005-next-feature/
+โ โโโ spec.md
+โโโ ...
+```
+
+Sequential numbers are coordinated across both directories. The next feature (in either directory) uses the next available number by scanning both. If `specs/004-*` is the highest, the next feature is `005-*` regardless of which framework creates it.
+
+Review both directories for a complete chronological timeline of all features.
+
+Use `/speckit.specify` (or the equivalent OpenSpec command) to create a new feature specification.
diff --git a/ruff.toml b/ruff.toml
new file mode 100644
index 0000000..3819426
--- /dev/null
+++ b/ruff.toml
@@ -0,0 +1,22 @@
+line-length = 99
+indent-width = 4
+target-version = "py39"
+
+[lint]
+select = [
+ "B", # flake8-bugbear
+ #"DTZ", # flake8-datetime
+ #"E", # pycodestyle
+ #"F", # Pyflakes
+ #"I", # isort
+ #"PLE", # pylint-error
+ #"SIM", # flake8-simplify
+ #"T10", # flake8-debugger
+ #"UP", # pyupgrade โ existing scripts use typing.Dict/List; leave off to avoid churn
+ #"W", # pycodestyle
+ #"YTT", # flake8-2020
+]
+
+ignore = [
+ "B904",
+]