Skip to content

feat(skills): add experimental mural skill with embedded MCP server, instructions, and agent integrations#1561

Open
WilliamBerryiii wants to merge 23 commits into
mainfrom
mural-mcp-skill
Open

feat(skills): add experimental mural skill with embedded MCP server, instructions, and agent integrations#1561
WilliamBerryiii wants to merge 23 commits into
mainfrom
mural-mcp-skill

Conversation

@WilliamBerryiii
Copy link
Copy Markdown
Member

@WilliamBerryiii WilliamBerryiii commented May 11, 2026

Pull Request

Description

Adds the experimental Mural skill — a Python-based CLI plus embedded stdio MCP server for the Mural REST API — together with the cross-cutting instruction set, agent integrations, collection registrations, documentation, and supporting validation guards needed to operate it.

The skill enables agents (DT Coach, RAI Planner, UX/UI Designer) to seed and extract Mural workspaces, rooms, murals, and widgets while honoring the Mural-as-human-record contract: AI never silently authors decisions, all writebacks remain inspectable in Mural, and operator logs never echo raw URLs, SAS query strings, OAuth tokens, or Authorization headers.

Key changes by area:

  • Skill: New .github/skills/experimental/mural/ package with bash and PowerShell entry scripts, a Python CLI (scripts/mural.py), an embedded MCP stdio server, polyglot Atheris fuzz harness, full pyproject.toml with ruff/pytest config, SECURITY.md, and .env.example.
  • Instructions: Six new cross-cutting instruction files under .github/instructions/experimental/mural/ covering destinations registry, human-record contract, log hygiene, seeding patterns, writeback hygiene, and asymmetric writing style; plus an open destination registry (destinations/registry.yml).
  • Agent integrations: Mural seeding/writeback wiring added to dt-coach.agent.md, rai-planner.agent.md, and ux-ui-designer.agent.md.
  • Collections: hve-core-all and project-planning collections register the skill and all six instructions at experimental maturity; entries alphabetized and tables reformatted via format:tables.
  • Docs: New mural credentials guide (docs/security/mural-credentials.md) wired into the Docusaurus sidebar; security model (docs/security/security-model.md) extended with sixteen Mural-skill threats (OA-1 .. OA-16) covering runtime, OAuth, and writeback surfaces.
  • Scripts/validation: validate:skills now requires the ruff isort (I) rule when a Python skill ships a tests/ directory, with matching Pester tests.
  • Plugin output: Regenerated plugins/** artifacts for both affected collections (autogenerated; do not hand-edit).

Related Issue(s)

Closes #1562

Type of Change

Code & Documentation:

  • Bug fix (non-breaking change fixing an issue)
  • New feature (non-breaking change adding functionality)
  • Breaking change (fix or feature causing existing functionality to change)
  • Documentation update

Infrastructure & Configuration:

  • GitHub Actions workflow
  • Linting configuration (markdown, PowerShell, etc.)
  • Security configuration
  • DevContainer configuration
  • Dependency update

AI Artifacts:

  • Reviewed contribution with prompt-builder agent and addressed all feedback
  • Copilot instructions (.github/instructions/*.instructions.md)
  • Copilot prompt (.github/prompts/*.prompt.md)
  • Copilot agent (.github/agents/*.agent.md)
  • Copilot skill (.github/skills/*/SKILL.md)

Other:

  • Script/automation (.ps1, .sh, .py)
  • Other (please describe):

Sample Prompts (for AI Artifact Contributions)

User Request:

"Use the mural skill to seed our discovery mural with the affinity clusters from the DT session,."

Execution Flow:

  1. The DT Coach agent loads .github/skills/experimental/mural/SKILL.md and the cross-cutting mural-*.instructions.md set.
  2. Coach invokes the mural CLI (scripts/mural.sh / mural.ps1) or the embedded stdio MCP server, authenticating via OAuth credentials sourced from environment / keyring per mural-credentials.md.
  3. Outbound writeback follows mural-seeding-patterns.instructions.md (duplicate-then-populate, anchor inheritance, probe-before-bulk) and mural-writing-style.instructions.md (sticky-concise outbound).
  4. Inbound extraction hydrates context per the asymmetric writing style and respects reserved tags from mural-writeback-hygiene.instructions.md.
  5. All operator log lines pass through the skill's _redact() backstop; agents additionally avoid echoing URLs, SAS query strings, or Authorization headers per mural-log-hygiene.instructions.md.

Output Artifacts:

  • New / updated Mural widgets (sticky notes, areas, tags, hyperlinks).
  • Coaching-state file updates derived from extracted widget contents.
  • Optional local JSON snapshots of murals/widgets when invoked through the CLI.

Success Indicators:

  • Mural reflects the seeded structure with reserved tags preserved and no duplicated reserved-tag widgets.
  • Operator logs contain no raw URLs, query strings, or token material.
  • Coaching state captures inbound extracts with full context per the inbound style contract.

Testing

Automated validation performed during PR preparation (commands run from repo root):

  • npm run lint:md — pass
  • npm run lint:yaml — pass
  • npm run lint:py — pass
  • npm run lint:ps — pass
  • npm run lint:frontmatter — pass
  • npm run lint:md-links — pass
  • npm run lint:marketplace — pass
  • npm run lint:collections-metadata — pass
  • npm run lint:ai-artifacts — pass
  • npm run lint:version-consistency — pass
  • npm run lint:permissions — pass
  • npm run lint:dependency-pinning — pass
  • npm run lint:links — pass
  • npm run lint:models — pass
  • npm run validate:skills — pass
  • npm run validate:copyright — pass
  • npm run plugin:generate — clean (no diff after regen)
  • npm run test:ps — 2178 passed, 0 failed, 3 skipped, 65 not-run
  • npm run test:py — mural skill tests pass. Two failures in unrelated skills are pre-existing:
    • tts-voiceovertests/test_embed_audio.py collection error: ModuleNotFoundError: No module named 'lxml'
    • powerpointtests/test_generate_themes.py collection error: ModuleNotFoundError: No module named 'ruamel'

Diff-based assessments:

  • No customer data, secrets, or NDA content in the diff.
  • New CLI/MCP entry points (mural.py, mural.sh, mural.ps1) follow least-privilege patterns and rely on env/keyring for credentials.
  • New validate:skills guard (isort 'I' requirement) is additive; existing skills already comply.

Manual testing not performed in this PR.

Checklist

Required Checks

  • Documentation is updated (if applicable)
  • Files follow existing naming conventions
  • Changes are backwards compatible (if applicable)
  • Tests added for new functionality (if applicable)

AI Artifact Contributions

  • Used /prompt-analyze to review contribution
  • Addressed all feedback from prompt-builder review
  • Verified contribution follows common standards and type-specific requirements

Required Automated Checks

  • Markdown linting: npm run lint:md
  • Spell checking: npm run spell-check (N/A — not run during PR prep)
  • Frontmatter validation: npm run lint:frontmatter
  • Skill structure validation: npm run validate:skills
  • Link validation: npm run lint:md-links
  • PowerShell analysis: npm run lint:ps
  • Plugin freshness: npm run plugin:generate
  • Docusaurus tests: npm run docs:test (N/A — not run during PR prep)

Security Considerations

  • This PR does not contain any sensitive or NDA information
  • Any new dependencies have been reviewed for security issues
  • Security-related scripts follow the principle of least privilege

Highlights:

  • Sixteen new Mural-specific threats (OA-1 .. OA-16) are documented in docs/security/security-model.md covering script-runtime, OAuth, and writeback surfaces.
  • mural-log-hygiene.instructions.md is the operator contract; the skill's _redact() is a defense-in-depth backstop, not a license to log secrets.
  • New runtime deps for the skill (shapely, scipy, networkx, keyring) are scoped to the skill's pyproject.toml and PEP 723 inline metadata; no global dependency surface change.

GHCP Artifact Maturity

Warning

This PR includes experimental GHCP artifacts that may have breaking changes.

  • .github/skills/experimental/mural/SKILL.md
  • .github/instructions/experimental/mural/mural-destinations.instructions.md
  • .github/instructions/experimental/mural/mural-human-record.instructions.md
  • .github/instructions/experimental/mural/mural-log-hygiene.instructions.md
  • .github/instructions/experimental/mural/mural-seeding-patterns.instructions.md
  • .github/instructions/experimental/mural/mural-writeback-hygiene.instructions.md
  • .github/instructions/experimental/mural/mural-writing-style.instructions.md
File Type Maturity Notes
experimental/mural/SKILL.md Skill ⚠️ experimental New skill in .github/skills/experimental/
experimental/mural/mural-destinations.instructions.md Instructions ⚠️ experimental Open destination registry contract
experimental/mural/mural-human-record.instructions.md Instructions ⚠️ experimental Mural-as-human-record contract
experimental/mural/mural-log-hygiene.instructions.md Instructions ⚠️ experimental Operator log redaction contract
experimental/mural/mural-seeding-patterns.instructions.md Instructions ⚠️ experimental Cross-cutting seeding conventions
experimental/mural/mural-writeback-hygiene.instructions.md Instructions ⚠️ experimental Tag/parentId/hyperlink rules
experimental/mural/mural-writing-style.instructions.md Instructions ⚠️ experimental Asymmetric outbound/inbound style

GHCP Maturity Acknowledgment

  • I acknowledge this PR includes non-stable GHCP artifacts
  • Non-stable artifacts are intentional for this change

Additional Notes

  • npm run test:py reports two pre-existing failures (tts-voiceover missing lxml, powerpoint missing ruamel) in skills not modified by this PR. Tracking separately is recommended.
  • Plugin output under plugins/** is autogenerated by npm run plugin:generate (post-processed by lint:md:fix and format:tables); do not hand-edit those files.

Bill Berry added 11 commits May 10, 2026 20:59
…server

- ship Python CLI (scripts/mural.py) covering workspaces, rooms, murals, widgets, OAuth, and tagging
- expose the same surface as a stdio MCP server for chat-agent integration
- include OAuth bootstrap, PKCE, redaction, rate-limit handling, and credential storage
- add fuzz harness, ~140 corpus seeds, and pytest suite (~30 modules)
- bundle SKILL.md, SECURITY.md, .env.example template, and dt-sections asset

🎨 - Generated by Copilot
- mural-human-record, mural-log-hygiene, mural-writeback-hygiene baseline rules
- mural-seeding-patterns and mural-writing-style for cross-agent seeding conventions
- mural-destinations registry (yaml + instructions) for adapter-aware writeback

🎨 - Generated by Copilot
…-planner, and ux-ui-designer

- reference instructions/experimental/mural/ paths from each agent
- align with relocated mural seeding-patterns and writing-style guidance

🎨 - Generated by Copilot
… in hve-core-all and project-planning

- include experimental mural skill in both collections
- register all six experimental mural instructions for the relevant agents

🎨 - Generated by Copilot
- new docs/agents/mural/credentials.md walks through backend selection, oauth bootstrap, devcontainer setup, troubleshooting, and migration
- _category_.json registers a collapsible Mural section in the agents sidebar

📝 - Generated by Copilot
… threats

- add Mural Skill Runtime as a fifth component category with token cache and PKCE controls
- expand boundary table with the Mural Skill Runtime trust boundary
- add OAuth Authentication Threats catalog (OA-1 through OA-16) using the extended STRIDE row format
- cross-reference MCP Server Trust Analysis from supply-chain and AI threat sections

🔐 - Generated by Copilot
- Validate-SkillStructure errors when tests/ is present but [tool.ruff.lint].select omits 'I'
- new Pester guard exercises real ruff against an I001-violating fixture
- prevents silent import-order regressions across all Python skills

🛡️ - Generated by Copilot
- reorder mural instruction entries into alphabetic position
- widen tables in powerpoint, tts-voiceover, mural seeding, security-model

🎨 - Generated by Copilot
@WilliamBerryiii WilliamBerryiii requested a review from a team as a code owner May 11, 2026 05:33
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 11, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

OpenSSF Scorecard

Scorecard details
PackageVersionScoreDetails
pip/atheris 3.0.0 🟢 5.9
Details
CheckScoreReason
Maintained⚠️ 00 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 0
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Code-Review🟢 7Found 23/30 approved changesets -- score normalized to 7
Binary-Artifacts🟢 10no binaries found in the repo
Packaging⚠️ -1packaging workflow not detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions🟢 10GitHub workflow tokens follow principle of least privilege
SAST⚠️ 0no SAST tool detected
Fuzzing🟢 10project is fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
Security-Policy🟢 10security policy file detected
pip/backports-tarfile 1.2.0 UnknownUnknown
pip/cffi 2.0.0 UnknownUnknown
pip/colorama 0.4.6 UnknownUnknown
pip/coverage 7.13.5 UnknownUnknown
pip/cryptography 48.0.0 UnknownUnknown
pip/importlib-metadata 9.0.0 UnknownUnknown
pip/iniconfig 2.3.0 UnknownUnknown
pip/jaraco-classes 3.4.0 🟢 4.7
Details
CheckScoreReason
Packaging⚠️ -1packaging workflow not detected
Token-Permissions🟢 10GitHub workflow tokens follow principle of least privilege
Maintained🟢 57 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
Code-Review⚠️ 0Found 0/30 approved changesets -- score normalized to 0
Security-Policy🟢 10security policy file detected
SAST⚠️ 0no SAST tool detected
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
License⚠️ 0license file not detected
Fuzzing⚠️ 0project is not fuzzed
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
pip/jaraco-context 6.1.2 UnknownUnknown
pip/jaraco-functools 4.4.0 UnknownUnknown
pip/jeepney 0.9.0 UnknownUnknown
pip/keyring 25.7.0 UnknownUnknown
pip/keyrings-alt 5.0.2 UnknownUnknown
pip/more-itertools 11.0.2 UnknownUnknown
pip/networkx 3.6.1 UnknownUnknown
pip/numpy 2.4.4 UnknownUnknown
pip/packaging 26.2 UnknownUnknown
pip/pluggy 1.6.0 UnknownUnknown
pip/pycparser 3.0 UnknownUnknown
pip/pygments 2.20.0 UnknownUnknown
pip/pytest 9.0.3 UnknownUnknown
pip/pytest-cov 7.1.0 UnknownUnknown
pip/pytest-mock 3.15.1 UnknownUnknown
pip/pywin32-ctypes 0.2.3 🟢 3
Details
CheckScoreReason
Code-Review⚠️ 0Found 0/30 approved changesets -- score normalized to 0
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1packaging workflow not detected
Binary-Artifacts🟢 10no binaries found in the repo
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 9license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
pip/ruff 0.15.12 UnknownUnknown
pip/scipy 1.17.1 UnknownUnknown
pip/secretstorage 3.5.0 UnknownUnknown
pip/shapely 2.1.2 UnknownUnknown
pip/tomli 2.4.1 UnknownUnknown
pip/zipp 3.23.1 UnknownUnknown
pip/atheris 3.0.0 🟢 5.9
Details
CheckScoreReason
Maintained⚠️ 00 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 0
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Code-Review🟢 7Found 23/30 approved changesets -- score normalized to 7
Binary-Artifacts🟢 10no binaries found in the repo
Packaging⚠️ -1packaging workflow not detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions🟢 10GitHub workflow tokens follow principle of least privilege
SAST⚠️ 0no SAST tool detected
Fuzzing🟢 10project is fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
Security-Policy🟢 10security policy file detected
pip/backports-tarfile 1.2.0 UnknownUnknown
pip/cffi 2.0.0 UnknownUnknown
pip/colorama 0.4.6 UnknownUnknown
pip/coverage 7.13.5 UnknownUnknown
pip/cryptography 48.0.0 UnknownUnknown
pip/importlib-metadata 9.0.0 UnknownUnknown
pip/iniconfig 2.3.0 UnknownUnknown
pip/jaraco-classes 3.4.0 🟢 4.7
Details
CheckScoreReason
Packaging⚠️ -1packaging workflow not detected
Token-Permissions🟢 10GitHub workflow tokens follow principle of least privilege
Maintained🟢 57 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
Code-Review⚠️ 0Found 0/30 approved changesets -- score normalized to 0
Security-Policy🟢 10security policy file detected
SAST⚠️ 0no SAST tool detected
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
License⚠️ 0license file not detected
Fuzzing⚠️ 0project is not fuzzed
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
pip/jaraco-context 6.1.2 UnknownUnknown
pip/jaraco-functools 4.4.0 UnknownUnknown
pip/jeepney 0.9.0 UnknownUnknown
pip/keyring 25.7.0 UnknownUnknown
pip/keyrings-alt 5.0.2 UnknownUnknown
pip/more-itertools 11.0.2 UnknownUnknown
pip/networkx 3.6.1 UnknownUnknown
pip/numpy 2.4.4 UnknownUnknown
pip/packaging 26.2 UnknownUnknown
pip/pluggy 1.6.0 UnknownUnknown
pip/pycparser 3.0 UnknownUnknown
pip/pygments 2.20.0 UnknownUnknown
pip/pytest 9.0.3 UnknownUnknown
pip/pytest-cov 7.1.0 UnknownUnknown
pip/pytest-mock 3.15.1 UnknownUnknown
pip/pywin32-ctypes 0.2.3 🟢 3
Details
CheckScoreReason
Code-Review⚠️ 0Found 0/30 approved changesets -- score normalized to 0
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1packaging workflow not detected
Binary-Artifacts🟢 10no binaries found in the repo
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 9license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
pip/ruff 0.15.12 UnknownUnknown
pip/scipy 1.17.1 UnknownUnknown
pip/secretstorage 3.5.0 UnknownUnknown
pip/shapely 2.1.2 UnknownUnknown
pip/tomli 2.4.1 UnknownUnknown
pip/zipp 3.23.1 UnknownUnknown

Scanned Files

  • .github/skills/experimental/mural/uv.lock
  • plugins/hve-core-all/skills/experimental/mural/uv.lock

Comment thread .github/skills/experimental/mural/tests/test_credential_storage.py
Comment thread .github/skills/experimental/mural/tests/test_credential_storage.py
Comment thread .github/skills/experimental/mural/tests/test_credential_storage.py
Comment thread .github/skills/experimental/mural/tests/test_credential_storage.py
Comment thread .github/skills/experimental/mural/tests/test_mural_commands.py Fixed
Comment thread .github/skills/experimental/mural/tests/test_mural_transport.py Fixed
Comment thread .github/skills/experimental/mural/tests/test_mural_transport.py Fixed
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 11, 2026

Codecov Report

❌ Patch coverage is 82.34618% with 307 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.99%. Comparing base (8d3b095) to head (3b7c39f).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
.../experimental/mural/scripts/mural/_area_helpers.py 47.82% 48 Missing ⚠️
...skills/experimental/mural/scripts/mural/_layout.py 70.51% 46 Missing ⚠️
...ls/experimental/mural/scripts/mural/_validation.py 83.21% 46 Missing ⚠️
...s/experimental/mural/scripts/mural/_tag_helpers.py 71.32% 41 Missing ⚠️
.../skills/experimental/mural/scripts/mural/_oauth.py 88.88% 24 Missing ⚠️
...ls/experimental/mural/scripts/mural/_mcp_schema.py 80.35% 22 Missing ⚠️
...lls/experimental/mural/scripts/mural/_mcp_tools.py 74.62% 17 Missing ⚠️
...ls/experimental/mural/scripts/mural/_exceptions.py 74.60% 16 Missing ⚠️
...ills/experimental/mural/scripts/mural/_geometry.py 95.20% 14 Missing ⚠️
...lls/experimental/mural/scripts/mural/_mcp_stdio.py 83.13% 14 Missing ⚠️
... and 3 more

❗ There is a different number of reports uploaded between BASE (8d3b095) and HEAD (3b7c39f). Click for more details.

HEAD has 4 uploads less than BASE
Flag BASE (8d3b095) HEAD (3b7c39f)
pytest 5 1
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1561      +/-   ##
==========================================
- Coverage   85.46%   77.99%   -7.48%     
==========================================
  Files          82       74       -8     
  Lines       11802    13263    +1461     
==========================================
+ Hits        10087    10344     +257     
- Misses       1715     2919    +1204     
Flag Coverage Δ
pester 83.69% <100.00%> (+0.08%) ⬆️
pytest 70.58% <82.29%> (-18.11%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...kills/experimental/mural/scripts/mural/__init__.py 65.55% <ø> (ø)
...lls/experimental/mural/scripts/mural/_constants.py 100.00% <100.00%> (ø)
scripts/linting/Validate-SkillStructure.ps1 95.39% <100.00%> (+0.92%) ⬆️
...kills/experimental/mural/scripts/mural/_jsonrpc.py 94.02% <94.02%> (ø)
...s/experimental/mural/scripts/mural/_credentials.py 87.71% <87.71%> (ø)
...l/mural/scripts/mural/_skill_doc_reconciliation.py 82.97% <82.97%> (ø)
...ills/experimental/mural/scripts/mural/_geometry.py 95.20% <95.20%> (ø)
...lls/experimental/mural/scripts/mural/_mcp_stdio.py 83.13% <83.13%> (ø)
...ls/experimental/mural/scripts/mural/_exceptions.py 74.60% <74.60%> (ø)
...lls/experimental/mural/scripts/mural/_mcp_tools.py 74.62% <74.62%> (ø)
... and 6 more

... and 26 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Bill Berry added 4 commits May 10, 2026 22:48
…n terms

- add accessibility, security, and sustainability acronyms (ASVS, CAPEC, COGA, CSRD, ESRS, FAPI, PKCE, SSCM, SSDF, TCFD, VPAT)
- add generic technical terms used in mural skill and security docs
- ignore gitignored dependency-pinning-artifacts/ outputs

📝 - Generated by Copilot
shapely declares 'BSD-3-Clause AND LGPL-2.1-only' (LGPL refers to
bundled GEOS headers); compound expressions don't match allow-licenses,
so allow shapely as a per-package exception.

🔒 - Generated by Copilot
MDX v3 rejects <https://...> autolinks containing path separators as
malformed JSX, breaking the Docusaurus build for credentials.md and
security-model.md.

🔒 - Generated by Copilot
Comment thread .github/skills/experimental/mural/tests/test_mural_transport.py Fixed
Comment thread .github/skills/experimental/mural/tests/test_mural_transport.py Fixed
Bill Berry added 4 commits May 10, 2026 22:57
- replace '<43 chars' with 'fewer than 43 chars' in security-model.md to satisfy MDX v3 parser
- reformat tables in security-model.md and credentials.md after autolink edits

📝 - Generated by Copilot
…orkers

- update test_mural_commands.py token-store concurrency worker to catch Exception
- update test_mural_transport.py reactive and proactive refresh workers to catch Exception
- preserves intent: KeyboardInterrupt and SystemExit propagate; clears CodeQL py/catch-base-exception

🛡️ - Generated by Copilot
… dependency-review

- add backports-tarfile, cryptography, jaraco-classes, jaraco-context, jaraco-functools, keyrings-alt
- explain inline that PyPI metadata reports unknown despite upstream Apache-2.0/MIT/BSD-3-Clause/PSF-2.0 licensing
- unblocks GitHub Actions dependency-review for the mural skill keyring stack

📦 - Generated by Copilot
Copy link
Copy Markdown
Member

@bindsi bindsi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Verdict: 🛑 Request Changes

Thanks for the substantial work here — the threat-modelled SECURITY.md, the explicit STRIDE buckets, the fuzz harness, and the loopback / PKCE hardening are all in great shape. Two findings on the in-scope skill code are merge-blocking, and two PR-level concerns need addressing before this can be safely reviewed and merged.

Code-level findings (inline comments)

ID Severity File Summary
RI-1 🔒 HIGH .github/skills/experimental/mural/scripts/mural.py (_run_login, ~L2305) OAuth token-exchange silently follows 30x; defeats the SECURITY.md §B2 guarantee and PKCE protection on the code-for-token exchange
RI-2 📄 MEDIUM .github/skills/experimental/mural/scripts/mural.py (_load_env_file, L513) Function is dead code; SECURITY.md and SKILL.md describe it as the credential parser, but the real parser is FileBackend._read_all
RI-5 ⚠️ LOW–MEDIUM .github/skills/experimental/mural/scripts/mural.py (_validate_hyperlink, L2659) Missing URL-scheme allowlist; javascript: / data: accepted (defense-in-depth gap, fuzz seed already exists)

See inline comments for code, repro reasoning, and concrete patches.


PR-level findings

🟧 RI-3 (HIGH) — PR scope significantly exceeds its stated description

The PR description scopes this as "experimental Mural skill + cross-cutting instructions + agent wiring". The diff also bundles, undocumented in the description:

  • A complete model-catalog validation subsystem: scripts/linting/Test-ModelReferences.ps1, scripts/linting/Update-ModelCatalog.ps1, scripts/linting/model-catalog.json + schema, two *.Tests.ps1 files, .github/workflows/model-validation.yml, related package.json lint:models entry
  • .github/workflows/dependency-review.yml policy change (no rationale in description)
  • Many edits across agent/prompt files unrelated to Mural
  • prompt-frontmatter.schema.json, copilot-instructions.md, .cspell* changes

This is +30,515/-91 across 217 files spanning ~four distinct subsystems. Bundling them under a Mural-skill PR:

  • Hides the model-validation subsystem from reviewers focused on Mural OAuth/MCP security
  • Couples roll-back: reverting model-catalog requires reverting Mural changes, and vice versa
  • Makes git bisect and post-incident forensics harder
  • Violates the project's commit-message-scopes convention ((skills), (scripts), (workflows), (agents), (prompts) are all touched in one PR)

Requested action (preferred): split into at least three PRs before merge —

  1. Mural skill + instructions + agent wiring (the actual stated scope)
  2. Model-catalog validation subsystem (Test-ModelReferences, Update-ModelCatalog, model-catalog.json, model-validation.yml, related tests, package.json lint:models entry)
  3. Cross-cutting agent/prompt edits unrelated to Mural

If splitting is infeasible at this point, at minimum: amend the PR description to enumerate every subsystem in scope with rationale for shipping together, and add CODEOWNER reviewers for each subsystem touched.

🟨 RI-4 (LOW) — Documentation path drift in PR description

The PR description references docs/security/mural-credentials.md; the file is actually committed at docs/agents/mural/credentials.md. Update the description, and grep the diff for any other docs/security/mural-credentials strings (in SECURITY.md, SKILL.md, instruction files) that need re-pointing so users following the docs from the PR description don't hit 404s.


Audit caveat

Given the size of this PR (12,705-line mural.py alone), this review is a strategic security sampling — not a line-by-line audit. Functions explicitly verified end-to-end against SECURITY.md claims:

  • _redact / _REDACT_KEYS (line 271, 1352) — keys list looks correct, includes RFC 7521 / 8628 / 6749 §4.3 defense-in-depth entries plus code form-param and Azure SAS query strings
  • FileBackend._read_all / _write_all / _check_credential_file_permsO_NOFOLLOW, O_EXCL temp + os.replace, 0o077 umask, mode-0600 enforcement all match SECURITY.md §B3
  • _LoopbackHandler — single-shot, GET-only, Host-header check, suppressed access logs all present
  • _validate_redirect_uri — http-only, loopback-only (rejects [::1]), /callback path, no query/fragment
  • _validate_asset_url — https + Azure Blob suffix allowlist, rejects userinfo / fragment / IP literals
  • _NoRedirect / _TOKEN_OPENER — correctly blocks 30x… for callers that actually use it (see RI-1)
  • _parse_token_response — Content-Type guard, capped body, JSON-object guard
  • _read_frame / MURAL_MAX_FRAME_BYTES — chunked read, drains oversized frame to next boundary, FrameTooLarge raised
  • _validate_tool_input_schema — covers type / enum / length / numeric bounds / array items / required / additionalProperties

Functions not sampled in depth (recommend deeper review before merge): _select_profile, _acquire_cache_lock, _apply_refresh, _authenticated_request, _validate_mural_id, _maybe_elicit, _require_scope, _validate_tool_registry, MCP initialize handshake, elicitation framing, the entire _cmd_* CLI surface, the model-catalog PowerShell scripts, and the Validate-SkillStructure.ps1 isort guard.

I'd recommend at least one more reviewer with explicit OAuth/MCP-protocol expertise on the unsampled surface, and a separate reviewer for the model-catalog subsystem if RI-3 is not split out.


To clear this verdict

  1. Fix RI-1 (single-line default change + regression test)
  2. Fix RI-2 (delete the dead function or restore + document its behavior)
  3. Address RI-5 (one-line scheme allowlist)
  4. Resolve RI-3 (split or amend description + add reviewers)
  5. Resolve RI-4 (update PR description path)

Happy to re-review once these are addressed — the underlying engineering quality is high, and the issues above are localized.

Comment thread .github/skills/experimental/mural/scripts/mural.py Outdated
Comment thread .github/skills/experimental/mural/scripts/mural.py Outdated
Comment thread .github/skills/experimental/mural/scripts/mural.py Outdated
Bill Berry and others added 2 commits May 11, 2026 09:29
- default _run_login _http to _TOKEN_OPENER.open to enforce redirect block
- remove dead _load_env_file shim; align docs to FileBackend._read_all
- reject non-http/https/mailto hyperlink schemes in _validate_hyperlink

🔒 - Generated by Copilot
Bill Berry added 2 commits May 12, 2026 21:45
- carve scripts/mural.py into a scripts/mural/ package with focused modules
- update SECURITY.md, SKILL.md, and tests to reference the package layout
- close review minors RV-01/RV-02/RV-03 in constants and logout transparency test
- teach Validate-SkillStructure.ps1 to recurse for python package layouts

📦 - Generated by Copilot
…age layout

- update dt-coach, ux-ui-designer, and rai-planner agents to reference scripts/mural/
- refresh mural log-hygiene and seeding-patterns instructions for the package layout
- update security-model docs to point at the scripts/mural/ package

🔗 - Generated by Copilot

_TAG_MERGE_MAX_RETRIES = 3
_TAG_MERGE_BACKOFF_MIN_MS = 50
_TAG_MERGE_BACKOFF_MAX_MS = 200

# Spatial query feature flags. Both default off until widget rotation and
# parentId field semantics are verified against the live portal.
_ROTATION_ENABLED = os.environ.get("MURAL_SPATIAL_ROTATION_ENABLED", "0") == "1"
# Spatial query feature flags. Both default off until widget rotation and
# parentId field semantics are verified against the live portal.
_ROTATION_ENABLED = os.environ.get("MURAL_SPATIAL_ROTATION_ENABLED", "0") == "1"
_PARENTID_FILTER_ENABLED = os.environ.get("MURAL_SPATIAL_PARENTID_FILTER", "0") == "1"
)


_LINE_RE = re.compile(
# Profile names: 1-32 chars, leading alphanumeric or underscore, then
# alphanumeric / underscore / dot / hyphen. Rejects "..", path separators,
# whitespace, and empty strings.
_PROFILE_NAME_RE = re.compile(r"^[A-Za-z0-9_][A-Za-z0-9_.-]{0,31}$")
# explicit override. The ``authored-by-ai`` tag is auto-attached to every
# widget created by AI-driven flows so downstream consumers can distinguish
# AI-authored objects from human-authored ones.
_RESERVED_TAGS: frozenset[str] = frozenset({"authored-by-ai"})
# widget created by AI-driven flows so downstream consumers can distinguish
# AI-authored objects from human-authored ones.
_RESERVED_TAGS: frozenset[str] = frozenset({"authored-by-ai"})
_AUTHORED_BY_AI_TAG_TEXT = "authored-by-ai"
# Reserved tag text *prefixes* applied by composite/layout flows. Mutating
# these via tag tools requires `force_reserved=True` just like literal
# reserved tags. Kept as a separate registry so prefix membership is cheap.
_RESERVED_TAG_PREFIXES: tuple[str, ...] = (
"ai-author:",
)

_TAG_MERGE_MAX_RETRIES = 3
)

_TAG_MERGE_MAX_RETRIES = 3
_TAG_MERGE_BACKOFF_MIN_MS = 50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[skill] Add experimental Mural skill with CLI, embedded MCP server, and agent integrations

4 participants