API
Documentation Map
-
API Reference
-
Channel:
latest -
Source repo:
JaddaHelpifyr/jhf-pattern
API
Runtime Entry Surfaces
Read-only service contract
| Endpoint | Method | Auth | Purpose | Stability |
|---|---|---|---|---|
/healthz | GET | none | liveness | stable |
/readyz | GET | none | readiness | stable |
/versionz | GET | none | version and identity | stable |
/contractz | GET | none | read-only contract view | stable |
/fabric-presencez | GET | none | fabric discovery presence | stable |
/fabric-compatibilityz | GET | none | fabric compatibility/policy hints | stable |
/fabric-manifest.json | GET | none | runtime-served manifest | stable |
/fabric-plane-workspace-facts | GET | none | Pattern-owned Plane workspace and project binding facts for Fabric polling | stable |
/fabric-plane-membership-facts | GET | none | Pattern-owned session and role-mapping facts for Fabric polling | stable |
/metrics | GET | none | Prometheus-ready sync and contract observability surface | stable |
/openapi.json | GET | none | FastAPI schema | internal |
API Prefix
/api/v1
Fabric Pull Publications
These two routes exist so Fabric can read Pattern-owned local facts without forcing Plane, Heddle, or downstream consumers to scrape internal operator surfaces directly.
GET /fabric-plane-workspace-facts- exports local workspace, Plane project binding, sync-mode, and webhook posture facts
- truth owner stays
jhf-pattern - this route does not invent Fabric, Plane, or identity truth
GET /fabric-plane-membership-facts- exports local OIDC client, role-mapping, and membership-visibility contract facts
- truth owner stays
jhf-pattern-session-contract - Plane visibility truth still belongs to Fabric
- Mission Control v2 is published here as an admitted SSO surface with:
auth_modeadmitted_surfacerole_admin_postureverify_paths
Core Product Groups
Projects
-
/api/v1/projects -
/api/v1/projects/{project_id} -
/api/v1/projects/{project_id}/active-workflow -
/api/v1/projects/{project_id}/board -
/api/v1/projects/{project_id}/doctor -
/api/v1/projects/{project_id}/operator-dashboard -
auth:
- operator session
-
stability:
- active
-
example request:
GET /api/v1/projects/ops-signal-orchestra/operator-dashboard HTTP/1.1
Cookie: pm_session=<session>
- example response shape:
{
"project_id": "ops-signal-orchestra",
"mode": "active",
"doctor": {},
"integrations": {}
}
- active workflow summary:
- route:
GET /api/v1/projects/{project_id}/active-workflow
- purpose:
- machine-readable ownership, work-class, state-vocabulary, mutation, sync, and remediation contract for the active project workflow
- example response shape:
- route:
{
"workspace_model": "single_primary_repo",
"primary_repo_ref": {
"provider": "gitea",
"full_name": "JaddaHelpifyr/jhf-pattern"
},
"supported_work_classes": ["project_work", "case_linked_work", "system_runtime_work"],
"state_contract": {
"priority_order": ["conflicted", "quarantined", "approval_required"]
},
"mutation_contract": {
"requires_expected_version": true,
"silent_overwrite": false,
"manual_override_requirements": ["why", "expected_version"]
},
"sync_contract": {
"git_inbound": "webhook_first",
"git_poll_fallback_minutes": 5,
"webhook_liveness_supported": true
},
"fabric_consumer_contract": {
"available": true,
"state": "healthy",
"contract_family": "helpifyr-support-pattern-consumer-contract",
"workflow_scope": "next-active-project-workflow-wave",
"workflow_wave": "wave-4-hard-enforcement-and-lifecycle-completion",
"case_linked_work_semantics": ["conflicted", "degraded", "verification_required"],
"lifecycle_states": ["active", "stale", "forced-review-required", "reopen-eligible", "archive-eligible", "remain-open"],
"writeback_rules": [{"name": "verification-required-or-conflicted-or-quarantined"}],
"failure_heatmap": {"heatmap_mode": "consumer-visible"},
"case_timeline": {"timeline_mode": "consumer-visible"}
},
"fabric_combination_profiles": {
"available": true,
"state": "healthy",
"contract_family": "fabric-combination-profiles",
"owner_repo": "JaddaHelpifyr/helpifyr-fabric",
"consumer_repository": "JaddaHelpifyr/jhf-pattern",
"relevant_profile_keys": ["fabric-warp-shuttle", "fabric-all"],
"required_profile_keys": ["fabric-all"],
"optional_profile_keys": ["fabric-warp-shuttle"],
"published_invariant_keys": ["fabric-truth-owner", "no-local-bundle-semantic"]
},
"plane_fabric_drift": {
"state": "degraded",
"partial_visibility": true
},
"external_truth_summary": {
"state": "blocked",
"external_truth": true
},
"case_linked_lifecycle": {
"states": ["active", "stale", "forced-review-required", "reopen-eligible", "archive-eligible", "remain-open"]
},
"writeback_guardrails": {
"requires_expected_version": true,
"allowed_remediation_actions": ["retry_writeback", "refresh_metadata", "escalate_to_manual"]
},
"workspace_risks": {
"duplicate_attachment_risk": false
},
"lifecycle_visibility": {
"source_missing_count": 0
},
"branch_pr_pressure": {
"actionable_review_pressure": 1
}
}
Tasks and Lanes
-
/api/v1/projects/{project_id}/tasks -
/api/v1/projects/{project_id}/lanes -
auth:
- operator session
-
stability:
- active
-
example request:
PATCH /api/v1/projects/ops-signal-orchestra/tasks/OPS-001 HTTP/1.1
Cookie: pm_session=<session>
Content-Type: application/json
{"lane":"backlog","expected_version":"2026-04-01T00:00:00Z"}
Auth / App Login
-
GET /api/v1/auth/oidc/status- purpose:
- runtime-readable OIDC config plus admitted-surface posture
- purpose:
-
GET /api/v1/auth/oidc/session-contract- purpose:
- current session freshness, audience, scopes, role, admin posture, and verify-path contract
- purpose:
-
GET /api/v1/settings/app-login- purpose:
- identity summary plus admitted Mission Control app-login contract
- purpose:
-
admitted-surface contract:
surface_keymission-control-v2
auth_modeoidc_claim_projection
consumer_posturenative_oidc_session_consumer
- local session truth owner
jhf-pattern-session-contract
- upstream readiness owner
jhf-heddle
- projection truth owner
helpifyr-fabric
Reed Owner Facts
-
GET /api/v1/reed/owner-facts -
auth:
- operator session or equivalent admitted operator auth
-
stability:
- active
-
purpose:
- authenticated read-only owner surface for Reed to consume Pattern-owned adapter facts without mutation
-
fail-closed auth posture:
- missing auth returns
401 - stale OIDC operator auth returns
401 - insufficient role returns
403
- missing auth returns
-
source truth:
contracts/reed/module-adapter-manifest.v2.json
-
example response shape:
{
"schema_version": "1",
"surface_key": "pattern-reed-owner-facts-v1",
"read_only": true,
"auth_required": true,
"stale_auth_fails_closed": true,
"source_truth_owner": "JaddaHelpifyr/jhf-pattern",
"manifest": {
"schema_version": "2.0",
"manifest_key": "pattern-reed-module-adapter-manifest-v2",
"path": "contracts/reed/module-adapter-manifest.v2.json"
},
"adapters": [
{
"module_kind": "project",
"adapter_key": "pattern-project-adapter-v2",
"primary_surface": "/api/v1/projects/{project_id}/active-workflow",
"supported_modes": ["dry_run", "admitted"]
}
],
"discovery": {
"api_surface": "/api/v1/reed/owner-facts",
"docs_ref": "docs/REED_OWNER_FACTS.md"
}
}
- example response shape:
{
"id": "OPS-001",
"lane": "backlog",
"work_class": "project_work",
"work_item_truth_owner": "jhf-pattern",
"source_truth_owner": "gitea",
"source_reference_type": "issue",
"version_token": "2026-04-01T00:00:00Z",
"workflow_state": "partial_visibility",
"external_truth_state": null,
"external_truth": false,
"missing_context": false,
"partial_visibility": true,
"writeback_guard_state": "pending_confirmation",
"case_lifecycle_guard": null,
"lifecycle_completion_guard": null,
"consumer_remediation_actions": ["refresh_metadata"],
"updated_at": "2026-04-01T00:00:00Z"
}
- Wave 3 workflow enforcement metadata:
workflow_stateexternal_truth_stateexternal_truthmissing_contextpartial_visibility
writeback_guard_statecase_lifecycle_guardlifecycle_completion_guardconsumer_remediation_actions- Wave 4 hard-enforcement additions:
- task and review-action writebacks require
expected_version - stale or missing revision tokens return
409with machine-readable remediation metadata - successful review writebacks return
readback_required,expected_version, andcurrent_version - lifecycle completion projection carries
archive-eligible,remain-open,reopen-eligible, andforced-review-requiredas consumer-visible guards
- task and review-action writebacks require
- these fields are exposed on both project-task payloads and support-derived work payloads
- they are consumer-facing projections and do not redefine upstream Fabric ownership
- the completed cross-repo closure for the previous plan slice is documented in:
helpifyr-fabric#135jhf-pattern#107
- the next Plane-owned contract and implementation slice now continues in:
jhf-pattern#108jhf-pattern#109
- the Plane-owned enforcement wave in
jhf-pattern#109adds:- planning sync routes accept
expected_versionand reject stale writebacks with409conflict detail metadata - planning sync and discovery payloads surface
workflow_state,writeback_guard_state,external_truth_state,partial_visibility,missing_context, andconsumer_remediation_actions - Plane fallback and mirror mode readbacks expose
last_origin_system,pending_confirmation,readback_required, and owner-visible fallback metadata instead of treating issue-mirror fallback as healthy hidden sync
- planning sync routes accept
- the final Plane-owned closure pass is complete in:
jhf-pattern#110
- no additional repo-local API/MCP closure remainder was found for this plan slice
Agents and Handoffs
/api/v1/projects/{project_id}/agents/api/v1/projects/{project_id}/handoffs
Planning
-
/api/v1/projects/{project_id}/planning/cycles -
/api/v1/projects/{project_id}/planning/modules -
/api/v1/projects/{project_id}/planning/pages -
/api/v1/projects/{project_id}/planning/pages/sync-from-repo -
/api/v1/projects/{project_id}/planning/pages/{slug}/pull-from-repo -
/api/v1/projects/{project_id}/planning/pages/{slug}/push-to-repo -
auth:
- operator session
-
stability:
- active
-
example request:
POST /api/v1/projects/ops-signal-orchestra/planning/pages/readme/pull-from-repo HTTP/1.1
Cookie: pm_session=<session>
- example response shape:
{
"slug": "readme",
"sync_state": "in_sync",
"repo_path": "README.md"
}
Delivery
-
/api/v1/projects/{project_id}/delivery/pipelines -
/api/v1/projects/{project_id}/delivery/deployments -
/api/v1/projects/{project_id}/delivery/releases -
/api/v1/projects/{project_id}/delivery/environments -
/api/v1/projects/{project_id}/delivery/review-queue -
/api/v1/projects/{project_id}/delivery/review-queue/{provider}/{external_id}/create-task -
/api/v1/projects/{project_id}/delivery/review-queue/{provider}/{external_id}/actions -
/api/v1/projects/{project_id}/delivery/branch-queue -
/api/v1/projects/{project_id}/delivery/release-readiness -
/api/v1/projects/{project_id}/delivery/health-summary -
/api/v1/projects/{project_id}/delivery/branch-queue/{provider}/{branch_name}/create-task -
auth:
- operator session
-
stability:
- active
-
example request:
GET /api/v1/projects/ops-signal-orchestra/delivery/review-queue HTTP/1.1
Cookie: pm_session=<session>
- example response shape:
{
"items": [
{
"provider": "gitea",
"repository_label": "JaddaHelpifyr/ops-signal-orchestra",
"review_decision": "changes_requested",
"approval_count": 0,
"requested_reviewer_count": 1,
"changes_requested_count": 1,
"comment_count": 3,
"cycle_keys": ["sprint-1"],
"module_keys": ["api"],
"linked_tasks": [{"task_key": "GITEA-REV-12"}]
}
],
"repository_groups": ["JaddaHelpifyr/ops-signal-orchestra"],
"cycle_groups": ["sprint-1"],
"module_groups": ["api"]
}
- example branch hygiene response:
{
"items": [
{
"provider": "gitea",
"repository_label": "JaddaHelpifyr/ops-signal-orchestra",
"name": "feat/runtime-cleanup",
"freshness_state": "stale",
"age_days": 37,
"risk_reasons": ["stale-branch"],
"linked_tasks": [{"task_key": "GITEA-BR-FEAT-RUNTIME-CLEANUP"}]
}
],
"repository_groups": ["JaddaHelpifyr/ops-signal-orchestra"],
"freshness_groups": ["stale", "aging", "fresh", "default"]
}
- example release readiness response:
{
"items": [
{
"provider": "gitea",
"external_id": "42",
"name": "Release 1",
"tag": "v1.0.0",
"gate_state": "review",
"cycle_key": "release-1",
"module_key": "api",
"latest_pipeline_status": "succeeded",
"latest_deployment_status": "succeeded",
"linked_review_count": 1,
"risky_review_count": 1,
"gate_reasons": ["candidate-release", "reviews-need-attention"]
}
],
"blocked_count": 0,
"review_count": 1,
"ready_count": 0,
"published_count": 0
}
- example review action request:
POST /api/v1/projects/ops-signal-orchestra/delivery/review-queue/gitea/77/actions HTTP/1.1
Cookie: pm_session=<session>
Content-Type: application/json
{"state_action":"close","actor":"operator","expected_version":"2026-04-01T00:00:00Z"}
- example review action response:
{
"provider": "gitea",
"external_id": "77",
"requested_actions": ["close"],
"applied": true,
"details": {"state": "closed"},
"expected_version": "2026-04-01T00:00:00Z",
"current_version": "2026-04-01T00:03:00Z",
"readback_required": true,
"writeback_guard_state": "pending_confirmation",
"workflow_state": "verification_required",
"external_truth_state": "verification_required",
"consumer_remediation_actions": ["refresh_metadata", "retry_writeback", "open_diff_and_resolve", "mark_verification_complete", "escalate_to_manual"]
}
- example delivery health summary response:
{
"failing_pipelines": 1,
"failed_deployments": 1,
"active_environments": 2,
"releases_needing_attention": 1,
"latest_pipeline_green": false,
"deployment_healthy": false,
"risky_reviews_unresolved": true,
"open_handoffs": 1,
"doctor_errors": 0
}
Integrations
-
/api/v1/projects/{project_id}/integrations/gitea/* -
/api/v1/projects/{project_id}/integrations/github/* -
/api/v1/projects/{project_id}/integrations/gitlab/* -
/api/v1/projects/{project_id}/integrations/plane* -
/api/v1/projects/{project_id}/integrations/n8n-expert* -
/api/v1/projects/{project_id}/integrations/n8n-operator* -
auth:
- operator session plus configured provider/integration credentials
-
stability:
- mixed active/internal
-
example request:
POST /api/v1/projects/ops-signal-orchestra/integrations/plane/sync HTTP/1.1
Cookie: pm_session=<session>
- example response shape:
{
"project_id": "ops-signal-orchestra",
"sync_mode": "auto",
"result": "ok"
}
Adapter Sandbox Writes
-
/api/v1/projects/{project_id}/adapter-sandbox/writes -
/api/v1/projects/{project_id}/adapter-sandbox/writes/{scenario}/{idempotency_key} -
auth:
- admin operator session
-
stability:
- active (sandbox-only contract)
-
safety posture:
- fail-closed unless
ADAPTER_SANDBOX_WRITE_ENABLED=true - fail-closed unless
project_idmatchesADAPTER_SANDBOX_PROJECT_PREFIX(defaultsandbox-) - owner repo must be
JaddaHelpifyr/jhf-pattern
- fail-closed unless
-
supported scenarios:
projectsupportqarelease
-
write contract guarantees:
- idempotency by
(project_id, scenario, idempotency_key) - bounded retry + timeout contract
- readback payload with target key and target summary
- evidence payload with operator action reference
- idempotency by
-
handoff-aware write contract:
- optional
handoff_contextforproject/supportscenarios handoff_context.handoff_idmust exist in the same project- handoff task/agent mismatch returns
409and no mutation - response carries:
handoff_contextreadback.target_summary.handoff_contextevidence.handoff
- optional
-
example request:
POST /api/v1/projects/sandbox-acp-write/adapter-sandbox/writes HTTP/1.1
Cookie: pm_session=<session>
Content-Type: application/json
{
"scenario": "project",
"idempotency_key": "sandbox-write-001",
"timeout_ms": 1500,
"retry": { "max_attempts": 2, "backoff_ms": 0 },
"owner_attribution": {
"owner_repo": "JaddaHelpifyr/jhf-pattern",
"owner_actor": "sandbox-admin",
"owner_reason": "acp_w3_sandbox"
},
"handoff_context": {
"handoff_id": "H-ADAPTER-001",
"task_key": "SBX-PROJ-001",
"from_agent": "agent-main",
"to_agent": "agent-support"
},
"operation": {
"task_key": "SBX-PROJ-001",
"title": "Sandbox project write",
"lane": "backlog",
"status": "open"
}
}
- example response shape:
{
"scenario": "project",
"idempotency_key": "sandbox-write-001",
"status": "applied",
"idempotent_replay": false,
"attempts": 1,
"timeout_ms": 1500,
"owner_attribution": {
"owner_repo": "JaddaHelpifyr/jhf-pattern",
"owner_actor": "sandbox-admin",
"owner_reason": "acp_w3_sandbox"
},
"handoff_context": {
"handoff_id": "H-ADAPTER-001",
"task_key": "SBX-PROJ-001",
"from_agent": "agent-main",
"to_agent": "agent-support",
"status": "open",
"ownership_link_state": "linked"
},
"readback": {
"target_type": "task",
"target_key": "SBX-PROJ-001",
"target_summary": {
"task_key": "SBX-PROJ-001",
"lane": "backlog",
"status": "open",
"handoff_context": {
"handoff_id": "H-ADAPTER-001",
"task_key": "SBX-PROJ-001",
"from_agent": "agent-main",
"to_agent": "agent-support",
"status": "open",
"ownership_link_state": "linked"
}
}
},
"evidence": {
"event": "adapter_sandbox_write_applied",
"project_id": "sandbox-acp-write",
"handoff": {
"handoff_id": "H-ADAPTER-001",
"task_key": "SBX-PROJ-001",
"from_agent": "agent-main",
"to_agent": "agent-support",
"status": "open",
"ownership_link_state": "linked"
}
}
}
- inbound webhook auth contract:
- Plane webhook:
- route:
/api/v1/projects/{project_id}/integrations/plane/webhook - preferred secret header:
X-Plane-Webhook-Secret - compatibility inputs still accepted:
X-Webhook-Secret, querysecret - failure status when configured secret mismatches:
403
- route:
- ClawLedger approval callbacks:
- routes:
- canonical spindle pending read:
GET /api/approvals/jhf-spindle/pending
- legacy clawledger approval contract:
POST /api/approvals/clawledgerGET /api/approvals/clawledger/pendingPOST /api/approvals/clawledger/syncPOST /api/approvals/clawledger/{project_id}/{task_key}/decisionPOST /api/approvals/clawledger/decision
- compatibility aliases:
GET /api/v1/approvals/jhf-spindle/pendingGET /api/v1/approvals/clawledger/pending
- canonical spindle pending read:
- required header when configured:
X-ClawLedger-Token - failure status when configured secret mismatches:
401
- routes:
- Plane webhook:
Spindle Pending Approvals
- canonical route:
GET /api/approvals/jhf-spindle/pending
- legacy aliases:
GET /api/approvals/clawledger/pendingGET /api/v1/approvals/jhf-spindle/pendingGET /api/v1/approvals/clawledger/pending
- auth:
- header
X-ClawLedger-TokenwhenCLAWLEDGER_APPROVAL_SHARED_SECRETis configured - no cookie or operator session required for the inbound consumer path
- header
- query params:
project_idoptionallimitoptional, default50, range1-200
- response fields per item:
project_idtask_keypacket_idpacket_namepacket_typecompanyrisk_leveltarget_doctypetarget_namelanestatuscallback_urlcreated_atupdated_at
- error codes:
200pending approvals returned401shared secret configured and header mismatch422invalid query parameter shape
Auth
-
/api/v1/auth/me -
/api/v1/auth/dev-login -
/api/v1/auth/logout -
/api/v1/auth/gitea/* -
/api/v1/auth/github/* -
/api/v1/auth/gitlab/* -
/api/v1/auth/oidc/* -
auth:
- none for callback entry, operator/session/config dependent elsewhere
-
stability:
- internal
-
/api/v1/auth/oidc/status- returns the configured OIDC issuer, canonical client id, redirect URI, scopes, and discovered authorization endpoint used by Mission Control
Recovery / Operations
-
/api/v1/projects/{project_id}/freeze -
/api/v1/projects/{project_id}/unfreeze -
/api/v1/projects/{project_id}/snapshots -
/api/v1/projects/{project_id}/restore -
/api/v1/projects/{project_id}/audit -
auth:
- operator session
-
stability:
- active
Auth
- default write/read product access:
- operator session cookie
- development-only path:
- dev login when enabled
- callback/webhook surfaces:
- integration-specific secrets
Versioning
- product API prefix:
/api/v1
- no stronger public semver guarantee is claimed for the full REST surface
- breaking product contract changes should be documented in:
CHANGELOG.mddocs/INTEGRATIONS.mddocs/FABRIC_TOOL_PROFILE.md
Examples
curl http://<internal-runtime-redacted>:18081/healthz
curl http://<internal-runtime-redacted>:18081/versionz
curl http://<internal-runtime-redacted>:18081/contractz
curl http://<internal-runtime-redacted>:18081/fabric-manifest.json
For schema detail, use /openapi.json.
License: AGPLv3
Helpifyr: https://helpifyr.com