marketplace/bundles/plan-marshall/skills/manage-providers/SKILL.md
Provider management for external tool authentication — secure storage, interactive configuration, and REST client infrastructure
npx skillsauth add cuioss/plan-marshall manage-providersInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Provider management skill for plan-marshall. Stores credentials outside LLM reach in ~/.plan-marshall/credentials/ (under the machine-global home root, overridable via the PLAN_MARSHALL_HOME env var), handles all user interaction via Python scripts (the LLM never sees secrets), and provides a RestClient for authenticated HTTP requests.
Execution mode: Route to appropriate subcommand script via credentials.py dispatcher.
Prohibited actions:
_providers_core.pyConstraints:
chmod 700 on ~/.plan-marshall/credentials/os.open() with mode 0o600 (no umask race)os.path.realpath() (symlink protection)re.sub(r'[^a-zA-Z0-9._-]', '', name) (path traversal protection)Provider discovery uses a two-phase approach based on marshal.json declarations:
discover-and-persist): Scans PYTHONPATH for *_provider.py files, calls get_provider_declarations() on each, and persists the combined declarations to marshal.json under the providers key. The marshall-steward wizard runs this during project setup.list-providers): Reads provider declarations directly from marshal.json. No filesystem scanning occurs at runtime.Each provider module exports get_provider_declarations() returning a list of declaration dicts. Five fields are persisted to marshal.json (skill_name, category, verify_command, url, description); all other fields (display_name, default_url, header_name, header_value_template, verify_endpoint, verify_method, extra_fields) are wizard-time only and not stored. The default_url declaration field is mapped to url on persist; git providers resolve url from git remote get-url origin. The skill_name field uses bundle-prefixed format (e.g., plan-marshall:workflow-integration-sonar).
providers[].skill_name stays bundle-prefixed, but the credentials_config storage key is canonicalized to the prefix-stripped form (e.g. workflow-integration-sonar), matching the credential filename under ~/.plan-marshall/credentials/. Writes always key the block by that canonical form and drop any pre-existing key whose canonical form is the same, so a re-configure never leaves two shadow blocks for one provider; reads accept either spelling — an exact skill_name match first, then a canonical-equality scan.
Stale prefixed credentials_config keys written before this normalization are canonicalized transparently by _providers_core on the next credentials_config access — no operator action, no migration subcommand. The pass is idempotent: once every key is canonical it performs no write. When two source keys collapse onto one canonical key with differing bodies, the pass leaves both keys untouched rather than merging them, so no block is ever lost silently.
| Subcommand | Description |
|------------|-------------|
| configure | Create credential file with placeholder secrets |
| check | Check if credential is complete (no placeholders remaining) |
| discover-and-persist | Scan PYTHONPATH for provider modules and persist declarations to marshal.json |
| list-providers | List available credential providers from marshal.json |
| edit | Update non-secret fields (URL, auth type) |
| verify | HTTP connectivity test, writes verified_at timestamp into the credential file |
| list | List configured skills by scanning ~/.plan-marshall/credentials/ (no secrets in output) |
| remove | Remove credential file |
| ensure-denied | Add deny rules to the host platform's settings |
| migrate-home | Explicitly run the lazy legacy-path migration (~/.plan-marshall-credentials/ → ~/.plan-marshall/credentials/); reports migrated, already_migrated, or conflict |
plan-marshall:manage-providers:credentials
Three-step workflow — the LLM collects non-secret values, the script creates a file with placeholder secrets, and the user edits the file directly:
AskUserQuestionpython3 .plan/execute-script.py plan-marshall:manage-providers:credentials configure \
--skill {skill} --url {url} --auth-type {auth_type} [--scope global|project] \
[--extra KEY=VALUE ...]
warnings is present: relay each warning string to the user. A warning means a supplied --extra value (e.g. organization) disagreed with the project's pom.xml Sonar property; the script kept the supplied value but surfaces the mismatch so the user can reconcile it.needs_editing: true: Tell user to open the file path and replace placeholders with real secretspython3 .plan/execute-script.py plan-marshall:manage-providers:credentials check \
--skill {skill} [--scope global|project]
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials verify \
--skill {skill} [--scope global|project]
CLI args:
--skill <name> — Required. Skill name matching a credential extension--url <url> — Base URL (uses provider default if omitted)--auth-type none|token|basic — Auth type (uses provider default if omitted)--extra KEY=VALUE ... — Extra fields (e.g., --extra organization=cuioss project_key=cuioss_repo)For the Sonar provider on a Maven project, configure auto-derives organization and project_key from the project's pom.xml <sonar.organization> / <sonar.projectKey> properties when they are not supplied via --extra. When such a value IS supplied via --extra and disagrees with the pom-derived value, the supplied value is kept and a non-fatal mismatch warning is surfaced (see warnings / mismatches below).
Return statuses:
created — New file created. If needs_editing: true, user must edit the file to add secrets. May carry warnings (list of human-readable mismatch strings — relay each to the user) and mismatches (structured {field, supplied, pom_value} entries) when a supplied --extra value disagrees with the project's pom.xml Sonar property.exists_complete — File already exists with real secrets. LLM asks user whether to reuse.exists_incomplete — File exists but has placeholder secrets. LLM tells user to finish editing.python3 .plan/execute-script.py plan-marshall:manage-providers:credentials check \
--skill {skill} [--scope global|project]
Returns complete, incomplete, or not_found. Use after the user edits a credential file.
Run during project setup (typically by the marshall-steward wizard) to scan for provider modules and populate marshal.json:
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials discover-and-persist
Scans all PYTHONPATH directories (set by the executor) for *_provider.py files, loads each module, calls get_provider_declarations(), and writes the combined list to marshal.json under the providers key.
Return fields: status, action, count, providers (list of skill names).
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials list-providers
Reads the providers list from marshal.json (populated by discover-and-persist). Returns available credential providers (what CAN be configured), not what IS configured. Use this in wizard/menu workflows to discover providers.
If no providers are found, the output includes a hint to run discover-and-persist first.
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials list [--scope global|project|all]
Updates non-secret fields (URL, auth type) via CLI args, and idempotently upserts extra provider-config fields (e.g. organization, project_key) via --extra KEY=VALUE ... without dropping the stored token. For secret changes, the user edits the credential file directly.
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials edit \
--skill <name> [--url <url>] [--auth-type none|token|basic] [--scope global|project] \
[--extra KEY=VALUE ...]
Returns path and needs_editing status, plus extras_upserted (the list of extra-field keys written) when --extra was supplied. If secrets need updating, tell the user to edit the file at the returned path.
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials verify [--skill <name>] [--scope global|project]
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials remove [--skill <name>] [--scope global|project]
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials ensure-denied [--target global|project]
See standards/security-considerations.md for full threat model and implementation constraints.
Tests override the credentials directory via the PLAN_MARSHALL_CREDENTIALS_DIR environment variable (read at module import time in _providers_core.CREDENTIALS_DIR). This is a testing-only knob — not a user-facing setting. Tests should set it via monkeypatch.setenv before importing _providers_core, or patch _providers_core.CREDENTIALS_DIR directly and reload as needed.
The canonical argparse surface for credentials.py. The plugin-doctor analyzer (_analyze_manage_invocation.py) reads this section as source-of-truth for the manage-invocation-invalid and missing-canonical-block rules. Consuming docs xref this section by name instead of restating the command inline. See pm-plugin-development:plugin-script-architecture cross-skill-integration.md § "Script invocation in documentation".
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials configure \
[--skill SKILL] [--scope {global,project}] [--url URL] [--auth-type {none,token,basic}] \
[--extra KEY=VALUE ...]
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials edit \
[--skill SKILL] [--scope {global,project}] [--url URL] [--auth-type {none,token,basic}] \
[--extra KEY=VALUE ...]
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials check \
--skill SKILL [--scope {global,project}]
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials verify \
[--skill SKILL] [--scope {global,project}]
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials discover-and-persist \
[--providers PROVIDERS]
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials list-providers
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials find-by-category \
--category CATEGORY
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials list \
[--scope {global,project,all}]
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials remove \
[--skill SKILL] [--scope {global,project}]
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials ensure-denied \
[--target {global,project}]
python3 .plan/execute-script.py plan-marshall:manage-providers:credentials migrate-home
| Skill | Purpose |
|-------|---------|
| plan-marshall:marshall-steward | Invokes credential management via wizard and menu |
| plan-marshall:workflow-integration-sonar | First consumer of credential extension API |
| plan-marshall:extension-api | Discovery pattern reference |
| plan-marshall:tools-permission-doctor | Deny rule manipulation reference |
development
Domain-owned OpenRewrite log-line finding parser for the java-cui domain — parses the
development
Domain-owned OpenRewrite marker detection for the java-cui domain — scans Java/Kotlin sources for cui-rewrite TODO markers, categorizes them by recipe, and fails the gate on any detected marker
development
Operator control surface for the marshalld build server — enrol/drop a project in the machine-global registry (the opt-in enable signal and anti-laundering wall), manage the daemon lifecycle (start, stop, drain, status, install, upgrade) version-pinned to the verified bundle copy, and inspect the daemon's per-project interaction-audit log (read-only)
tools
The tiny build-consumption client for the marshalld build server — submit a build job, bounded long-poll for its result, ping the daemon identity, and preflight registry-plus-liveness in one call; consumption only, never provisioning or enrolment