Claude Personal Marketplace Support Readiness Runbook
Status: incomplete. Support readiness remains a publication blocker. Every
UNASSIGNED - BLOCKINGfield below needs an approved owner or value, and the mailbox, workflow-notification and rollback drills need recorded evidence. This runbook and a green synthetic check do not set a release gate topass.
This runbook covers support and incident response for the existing
skillpilot-coach-v1 personal-marketplace candidate and its dedicated remote
connector. It does not authorize publication, a production configuration
change, token or session revocation, or an expansion of the tested client
contract. The frozen OpenAI Coach v1 contract remains unchanged.
Approved Restricted Evidence Store
The Product Owner selected one private Google Drive folder as the restricted evidence store. It must remain owner-only, with link sharing disabled and MFA enabled on the owning account. Each completed release is retained as one final, immutable ZIP or PDF evidence bundle; a mutable native document alone is not sufficient evidence. The private account address, raw mailbox and alert delivery details, screenshots and other sensitive material stay outside this repository.
The approved store was created on 1 September 2026 under the existing private
SkillPilot Drive folder. A successful write and metadata readback reported
shared: false, exactly one owner permission and no public, domain, group or
link permission. The Product Owner separately confirmed that MFA is active on
the owning Google account. The private folder ID, URL, account details and MFA
evidence remain outside this repository. Public release records use the opaque
reference SP-CLAUDE-EVIDENCE-STORE-001 and retain only that reference plus
the SHA-256 of each final bundle.
Ownership And Support Boundary
| Responsibility | Current value | Readiness requirement |
|---|---|---|
| Public intake | support@skillpilot.com |
Mailbox round trip, access by the accountable responder and every assigned backup, and the current account-security or explicitly accepted residual-risk decision must be evidenced in the restricted store. |
| Accountable support owner | Dr. Matthias Unverzagt (also Product Owner) | Owns intake and incident declaration. |
| Backup support owner | None; Product Owner accepted the single-owner risk | Pause active public promotion during an unmonitored absence; the repository and existing installations need not be disabled solely because the owner is absent. |
| Operations owner | Dr. Matthias Unverzagt | Authorized to execute connector containment and recovery. |
| Security owner | Dr. Matthias Unverzagt | Owns credential, token and learner-session incidents. |
| Covered support hours | No fixed staffed window; best effort; no guaranteed SLA | Active public promotion pauses during an unmonitored absence. |
| Internal response objectives | Best effort; no guaranteed response time | On discovery of a security or privacy incident, pause promotion and contain the connector as necessary as soon as practicable. |
| Workflow alert route | Accountable owner's private GitHub notification route | The private delivery address stays only in restricted evidence; delivery and acknowledgement still require a drill. |
| Authenticated-tool detection | BEST-EFFORT REACTIVE BETA - ACCEPTED |
There is no host-side per-operation email monitor and no real-time detection or SLA claim. Signals are the best-effort scheduled public synthetic, the configured GitHub workflow-failure notification route, support reports and targeted inspection of the provider-bounded operation-error record. |
| Restricted revocation procedure | SP-CLAUDE-V1-IR-001 version 1.0.0 (draft; isolated rehearsal and approval still blocking) |
The operations and security owner is Dr. Matthias Unverzagt. The reviewed one-shot source and tests are scripts/claude_v1_revoke.py and scripts/test_claude_v1_revoke.py. Keep incident-specific commands, access details and evidence only in the approved restricted evidence store; never commit secrets or live values. |
The supported product boundary is the one documented in the Claude connector user guide and the personal marketplace release runbook. Support must not turn technical availability on another Claude client, plan or surface into a SkillPilot support claim without separate acceptance evidence.
Run The Audit
The synthetic is read-only. It sends only credential-free GET requests to a
fixed allowlist, rejects redirects, bounds response bodies and never prints
response bodies. It verifies the current immutable plugin publication, public
legal and privacy pages, application readiness, connector OAuth discovery and
the unauthenticated MCP challenge.
During a backend rollout, the publication check accepts either the exact immutable checked-in publication or the current publication reproduced locally with the backend's deterministic build generator. Both paths verify the entire index and the archive against locally checked release evidence; an arbitrary remote version or hash is never accepted. Temporary build resources are removed after the check. The reported candidate identifies the publication actually served. This availability check does not replace the deployment gate, which requires the exact newly built publication.
Run its unit tests and then the live check:
node --test scripts/claude_support_synthetic.test.mjs
node scripts/claude_support_synthetic.mjs verify
The implementation is claude_support_synthetic.mjs. The Claude Support Synthetic workflow runs the same unit tests and performs the live check on its schedule or through manual dispatch. Pull requests run only the unit tests and do not contact the production endpoints.
Inspect Results And Alerts
A passing JSON result contains the UTC check time, candidate version and SHA-256, and one bounded result per public check. It contains no local paths, credentials, learner data or response bodies. Preserve the JSON artifact and the immutable workflow-run URL in the approved evidence store.
A failed scheduled run is only a signal in GitHub Actions. It is not proven
alerting until the accountable recipient and every assigned backup actually
receive the notification. To test that route, manually dispatch the workflow with
exercise_alert enabled. The workflow first runs the real synthetic and then
fails intentionally. Record dispatch, delivery and acknowledgement timestamps
in the drill evidence. Never weaken the check merely to make the drill green.
Best-Effort Authenticated-Tool Detection Boundary
The public synthetic deliberately cannot exercise authenticated tools. On 3 September 2026, the Product Owner selected and accepted the following simpler operating boundary for the personal-marketplace beta:
- no host-side per-operation email monitor or additional systemd service;
- the production deployment must not add or retain a technical-mailbox or SMTP credential;
- no guaranteed real-time detection, staffed monitoring window or SLA;
- credential-free public checks scheduled hourly and the configured GitHub
workflow-failure notification route, plus reports received through
support@skillpilot.com; and - targeted inspection by the authorized operations owner of the existing provider-bounded Claude v1 operation-error record, whose application message contains only the operation name and duration.
An authenticated operation failure can therefore remain unknown until a support report, a related public-surface failure or a manual check exposes it. GitHub workflow scheduling and notification delivery are themselves best effort and may be delayed. That residual risk is accepted only for the current best-effort personal- marketplace beta. Public material must not imply proactive per-tool monitoring, real-time detection or guaranteed response times.
This boundary neither satisfies nor duplicates the separate exact-client acceptance gate, which remains independently blocking. During a reported incident, reproduce authenticated behavior only when necessary and only with the authorized adult test context; never use customer credentials or learner state. After recovery, repeat the affected clean-client checks and the public synthetic.
Reassess managed structured observability, durable delivery with retries and an independent monitor health signal before any institutional, Directory, staffed, SLA-backed or general-availability claim. Such an expansion is a separate release and operations decision, not part of this beta runbook.
Safe Intake
Ask only for the minimum information needed to route a report:
- UTC time and whether the failure was during marketplace add, installation, connector authorization, first-party start, or normal use;
- installed plugin version and the marketplace repository revision if visible;
- Claude plan class and client surface, without account identifiers;
- sanitized error text and the relevant synthetic workflow-run URL.
Never request or retain a permanent SkillPilot ID, an spc_ learner-session
value, a prepared q URL, OAuth code or token, cookie, capability, complete
chat transcript, or screenshot containing learner data. If one arrives
unexpectedly, stop copying it, restrict access and route it to the security
owner under the approved incident process.
Triage And Troubleshooting
| Signal | First safe action | Escalation |
|---|---|---|
| Immutable publication, legal or privacy check fails | Stop rollout promotion and rerun the synthetic once from a clean environment. Do not replace published bytes or force-push marketplace history. | Operations owner; security owner too if integrity or disclosure is suspected. |
Application readiness is not UP |
Check the approved service and deployment telemetry; do not ask a learner to retry repeatedly. | Operations owner and incident declaration according to the approved response objective. |
| OAuth metadata or MCP Bearer challenge differs | Treat connector authorization as fail-closed. Do not ask for an OAuth code or token. | Security and operations owners. |
| Marketplace cannot be added or the plugin is absent | Confirm the full HTTPS marketplace repository URL, eligible supported plan/surface, and one refresh. Preserve only the sanitized client error. | Support owner; release owner if reproducible on the clean acceptance account. |
| Connector authorization fails | Check the public discovery synthetic. Ask the user to restart authorization only after the public contract is healthy. | Security owner for loops, unexpected consent, or leaked values. |
| A connected client rejects the learner session | Start a new session only through https://skillpilot.com/; never accept the session value by email. |
Support owner; operations owner if reproducible with an authorized synthetic fixture. |
| An authenticated tool fails while the public synthetic passes | Reproduce only if needed with the authorized adult test fixture, then filter for the provider-bounded Claude v1 operation-error record without copying surrounding journal records or raw learner data. | Operations and security owners; pause promotion if integrity, privacy or a systematic fault is suspected. |
| Provider-wide client failure while SkillPilot checks pass | Record the provider status as an external dependency and avoid changing SkillPilot bytes. | Support owner monitors recovery; no SkillPilot rollback without SkillPilot evidence. |
Restricted Revocation Tool Contract
SP-CLAUDE-V1-IR-001 is a root-only, one-shot incident tool, not a daemon,
endpoint or normal deployment step. Install only the reviewed source from the
exact approved commit. First verify that this path is unchanged in that commit,
record its SHA-256, then install it byte-identically:
SKILLPILOT_APPROVED_COMMIT=REVIEWED_40_CHARACTER_COMMIT
test "$(git rev-parse --verify HEAD^{commit})" = \
"${SKILLPILOT_APPROVED_COMMIT}"
git ls-files --error-unmatch scripts/claude_v1_revoke.py
git cat-file -e \
"${SKILLPILOT_APPROVED_COMMIT}:scripts/claude_v1_revoke.py"
git diff --exit-code "${SKILLPILOT_APPROVED_COMMIT}" -- \
scripts/claude_v1_revoke.py
sha256sum scripts/claude_v1_revoke.py
sudo install -d -o root -g root -m 0755 \
/usr/local/libexec/skillpilot
sudo install -o root -g root -m 0755 \
scripts/claude_v1_revoke.py \
/usr/local/libexec/skillpilot/claude_v1_revoke
sudo sha256sum /usr/local/libexec/skillpilot/claude_v1_revoke
sudo stat -c '%U:%G %a %n' \
/usr/local/libexec/skillpilot/claude_v1_revoke
The two hashes must match and the installed metadata must be exactly
root:root 755. Never run the deploy user's writable source copy. The
installed tool refuses another path, owner or mode. It derives one candidate
PostgreSQL connection only from the five POSTGRES_* values inherited by the
uniquely identified SkillPilot application JVM inside the active
skillpilot.service cgroup, passes only those values to psql, and never
prints them. The connected server returns a non-secret targetSha256 binding
the database name, effective database role, database OID, server address and
port, and PostgreSQL postmaster start time. This deliberately supports the
current bootRun service topology, whose systemd MainPID can be the Gradle
wrapper rather than the application JVM. It invokes only fixed,
PATH-independent system-command anchors. A regular anchor is accepted
directly. A distribution-managed symlink anchor is accepted only through a
bounded, cycle-free chain in which every link is root:root, every lexical
parent directory is root-owned and not writable by group or others, and the
final target is a root:root, non-writable regular executable without special
mode bits. The resolved final target, not the symlink anchor, is executed. It
fails closed if the service exposes a
direct Spring datasource, config or profile override, an external
application* configuration file in a default search location, another
EnvironmentFile, an unexpected database-name shape, more or fewer than one
matching application JVM, or a changing service process.
This is an operational guard, not host-attestation. It does not introspect
Spring objects and cannot independently prove which datasource a modified
application classpath selected. It trusts the host's root boundary, systemd
unit, running process, inherited environment and deployed application
classpath. The current bootRun classpath is writable by the deployment user.
If host, deployment-account, checkout, process, configuration or classpath
integrity is in doubt, do not run execute on that host. Keep the public edge
contained, perform revocation from an independently verified DBA-controlled
database path, and rebuild the host from reviewed immutable artifacts. Moving
production to a digest-bound, root-owned immutable application artifact is a
separate hardening improvement before a broader-than-beta rollout.
Before support readiness can pass, run only its read-only production plan and retain the single sanitized JSON result in the restricted evidence store:
sudo /usr/local/libexec/skillpilot/claude_v1_revoke plan \
--procedure-id SP-CLAUDE-V1-IR-001 \
--incident-id SPDRILL-YYYYMMDD-NNN
plan validates the connected production schema, migrations, exact Claude-v1
scope and database-target guards without changing a row. The owner must review
whether the four aggregate counts are plausible and retain targetSha256 with
the plan. A database restart, failover, changed role or changed connection
target changes that fingerprint and invalidates the plan. Unexpected counts or
any failed guard stop the procedure; they are not repaired by broadening the
scope. The REVIEWED_40_CHARACTER_COMMIT placeholder deliberately keeps the
installation example inert until the approved commit exists.
The prepublication plan never authorizes an execute. During an actual
incident, replace the installed active Claude-v1 vhost bytes at the same include
path with the reviewed deny-only
skillpilot-claude-connector-v1-contained.conf,
set the Claude-v1 backend flag to false, restart the shared service to
readiness, validate Nginx and reload it. The root-owned containment file must be
mode 0644; its source and installed SHA-256 must match. A fresh TLS request to
/mcp must return both HTTP 404 and
X-SkillPilot-Claude-V1-Containment: SP-CLAUDE-V1-CONTAINED-1. This distinctive
response proves that a new connection reached the loaded deny-only generation,
not merely a disabled backend through an old proxy worker.
sha256sum deploy/nginx/skillpilot-claude-connector-v1-contained.conf
sudo install -o root -g root -m 0644 \
deploy/nginx/skillpilot-claude-connector-v1-contained.conf \
/etc/nginx/skillpilot-claude-connector-v1.conf
sudo sha256sum /etc/nginx/skillpilot-claude-connector-v1.conf
sudo nginx -t
sudo systemctl reload nginx
curl --silent --show-error --proto '=https' --max-time 10 --dump-header - \
--output /dev/null \
https://mcp-claude-v1.skillpilot.com/mcp
Then repeat plan with the incident's SPINC-... identifier. Only then may the
security owner copy those four fresh counts, that plan's targetSha256 and its
toolSha256 into an execute using the same incident identifier:
sudo /usr/local/libexec/skillpilot/claude_v1_revoke plan \
--procedure-id SP-CLAUDE-V1-IR-001 \
--incident-id SPINC-YYYYMMDD-NNN
sudo /usr/local/libexec/skillpilot/claude_v1_revoke execute \
--procedure-id SP-CLAUDE-V1-IR-001 \
--incident-id SPINC-YYYYMMDD-NNN \
--expect-oauth PLAN_OAUTH_COUNT \
--expect-consents PLAN_CONSENT_COUNT \
--expect-sessions PLAN_SESSION_COUNT \
--expect-idempotency PLAN_IDEMPOTENCY_COUNT \
--expect-target-sha256 PLAN_TARGET_SHA256 \
--expect-tool-sha256 PLAN_TOOL_SHA256 \
--confirm REVOKE-CLAUDE-V1-AUTHORIZATIONS-AND-SESSIONS
The placeholders deliberately make this example non-executable. execute
requires all values, the exact tool hash, the Claude-v1 flag explicitly
false, an unchanged running service and the exact root-owned deny-only Nginx
vhost at /etc/nginx/skillpilot-claude-connector-v1.conf. The proxy check binds
that file's SHA-256, verifies that the loaded on-disk configuration contains no
Claude-v1 upstream, and requires the distinctive header plus 404 from a fresh
credential-free loopback TLS request. It locks the six involved tables before
the destructive transaction takes its first snapshot. This can briefly delay
OAuth writes for other providers, while reads remain available. Row-level
security, table inheritance, unexpected cascading foreign keys, user DELETE
triggers or rewrite rules abort before mutation. The transaction either deletes
the exact current Claude-v1 aggregate scope or rolls back. The target
fingerprint must still match after the table locks are acquired, so a stale plan
from a different database instance, role, endpoint or postmaster generation is
rejected. It forces synchronous local commit and refuses a PostgreSQL server
with fsync disabled so a reported commit is not merely buffered process
state.
The result is always one sanitized JSON object. status: "applied" is the only
ordinary success. status: "applied_but_containment_unverified" means the
reported aggregate deletion counts committed but the final service or live
containment recheck failed. status: "apply_outcome_unverified" means the
database client did not return trustworthy commit evidence; only the expected
counts and expected target fingerprint are reported. For either non-success
status, keep containment in place, run a fresh plan to establish the current
state, and never retry with guessed or stale values.
Any change to the procedure's scope, SQL, guards, CLI/operator contract or
database-target resolution requires a new procedure version, a new isolated
rehearsal, review, and byte-identical production installation. Earlier
evidence becomes stale. Version 1.0.0 must never name different destructive
semantics.
Incident Containment And Recovery
- Open an incident record, assign severity and owners, record UTC detection, and pause new marketplace promotion. Keep all sensitive evidence in the approved restricted store.
- Determine whether the fault is marketplace distribution, the SkillPilot connector, the shared application, or an external Claude client. Preserve the last passing candidate-bound synthetic result.
- For a connector integrity or data-boundary incident, an authorized operator follows the disable order in the connector rollback drill. Those production actions require incident authority; this runbook does not execute them.
- The security owner runs a fresh
plan, checks its aggregate counts and target fingerprint, and invokes the count-, target- and tool-hash-boundexecuteform of the approved restricted revocation procedure. It revokes both Claude-v1 transport authorizations and independent Claude-v1 learner sessions, is irreversible, and must never restore revoked credentials from a backup. Use only the installed copy described above. Until the versioned procedure has passed its isolated rehearsal, read-only production plan and approval, support readiness cannot pass. - Repeat the frozen OpenAI differential checks after containment and before recovery. A Claude response must not silently alter the OpenAI v1 edge, package, tools, schemas, UI, sessions or review artifacts.
- Recover only from a reviewed immutable candidate. Marketplace-content
rollback is a new higher-SemVer release; never reuse a version with different
bytes, delete history or force-push
main. - Close the incident only after the synthetic, clean-client acceptance and relevant rollback/recovery checks pass and the accountable owners sign off.
Two-Part Prepublication Rehearsal
The personal-marketplace beta proves revocation and production recovery in two separate exercises. This avoids deleting real user credentials merely to test an emergency control, while still exercising the exact destructive procedure before it is needed under incident pressure.
- Restricted-revocation readiness. The repository integration test runs
the exact embedded transaction from
SP-CLAUDE-V1-IR-001version1.0.0against a disposable PostgreSQL database containing dedicated Claude-v1 fixtures plus negative OpenAI and retired-Claude-beta controls. It must also prove rollback on a late failure, resistance to a poisonedsearch_path, exclusion of a concurrent OAuth writer, rejection of row-level security and table inheritance, and rejection of unexpected cascades, DELETE triggers and contradictory provider/principal shapes. The transaction must delete only the provider/version-scoped Claude-v1 OAuth authorizations and Claude-v1 learning sessions while preserving the negative controls and durable curriculum/mastery state outside those sessions. Separately, install the same source byte-identically asroot:rootmode0755and run only its read-onlyplanagainst production. Retain only aggregate counts, the non-secret target fingerprint, timestamps, procedure/version hashes and pass/fail results; never retain row values, tokens, session hashes or learner identifiers. - Production containment/recovery rehearsal. In an explicitly approved
maintenance window, pause promotion, replace only the Claude-v1 TLS vhost
with the reviewed deny-only containment vhost and reload Nginx, set the
Claude-v1 feature flag to
false, restart the shared service, and prove the distinctive containment response while application readiness and the frozen OpenAI v1 differential remain healthy. Re-enable the unchanged known-good backend flag, restart the service and prove readiness while the deny-only vhost remains loaded; only then restore the same reviewed active TLS vhost and reload Nginx. Do not redeploy unchanged artifacts merely for the drill. Then repeat the live synthetic and required clean adult test-client check and record the observed interruption.
The Product Owner accepted on 3 September 2026 that the production rehearsal does not bulk-revoke real OAuth grants or learner sessions. Production-wide revocation is reserved for an actual security or data-boundary incident and is then executed only after containment by the authorized operations/security owner. Recovery after revocation means a fresh OAuth connection and a new first-party learning session; it never means restoring revoked records.
This two-part beta evidence does not weaken or satisfy the stricter independent Connector Directory rollback gate in the connector release runbook.
Record The Drill
Use the support-readiness drill template as a checklist, then store the completed evidence outside the public repository. Record the accepted best-effort boundary and reference the separate sanitized deployment and drill evidence; do not retain raw tool arguments, learner state, logs or credentials. The committed file is intentionally a pending candidate template and is not release evidence.
Minimum Pass Criteria
Support readiness can be changed to pass only in a separate, approved status
change after all of these are true for the exact candidate, source commit and
reproducible marketplace-tree SHA-256:
- accountable support, operations and security owners are named, have the required access, and approve the support boundary; one person may hold multiple roles, and a missing backup requires an explicitly accepted single-owner contingency that pauses public promotion during absence;
- the public support mailbox completes inbound and outbound round trips with every assigned responder, without auto-reply or spam-routing ambiguity;
- the actual coverage boundary, including the absence of a fixed staffed window, and the internal severity/response objectives are approved without publishing an unsupported SLA;
- the scheduled synthetic is enabled, its latest candidate-bound run passes, and its sanitized JSON and immutable run URL are retained;
- the intentional failed-run drill reaches the accountable alert path and every assigned backup path, with receipt and acknowledgement timestamps retained;
- the Product Owner has accepted the best-effort authenticated-tool detection boundary, candidate-specific deployment evidence confirms that no host-side WARN-to-email service or SMTP credential is installed for it, and neither release nor support material claims real-time monitoring or an SLA;
- the exact versioned restricted revocation procedure has passed the isolated disposable-database rehearsal, including negative OpenAI and retired-beta controls, transaction rollback, fixed-schema, concurrent-writer, row-level security, table-inheritance, cascade, trigger and provider-scope checks, without learner data, credentials or row values in evidence;
- its byte-identical production copy is installed as
root:rootmode0755, the trusted-host precondition is explicitly confirmed, and a successful read-onlyplanhas validated the configured running-service connection, target fingerprint and connected production schema without a database mutation; - the production connector containment, frozen OpenAI differential and known-good recovery rehearsal has passed in an approved maintenance window, without bulk-revoking real credentials and with the observed shared-service interruption recorded;
- at least one sanitized support scenario is triaged end to end by the accountable responder and, when assigned, one by the backup; without a backup, the single-owner absence and promotion-pause contingency is rehearsed instead; and
- the Product Owner reviews the complete evidence and explicitly authorizes the later gate-status change.
Missing, stale or candidate-mismatched evidence fails closed. A green synthetic, a populated template, or a configured email address alone is never sufficient. The remote marketplace revision does not exist before first publication and is therefore not a support-readiness prerequisite. Bind it in the later repository-verification and exact-client activation evidence once it exists.