Skip to main content

API

Documentation Map

API

Runtime Entry Surfaces

Read-only service contract

EndpointMethodAuthPurposeStability
/healthzGETnonelivenessstable
/readyzGETnonereadinessstable
/versionzGETnoneversion and identitystable
/contractzGETnoneread-only contract viewstable
/fabric-presencezGETnonefabric discovery presencestable
/fabric-compatibilityzGETnonefabric compatibility/policy hintsstable
/fabric-manifest.jsonGETnoneruntime-served manifeststable
/fabric-plane-workspace-factsGETnonePattern-owned Plane workspace and project binding facts for Fabric pollingstable
/fabric-plane-membership-factsGETnonePattern-owned session and role-mapping facts for Fabric pollingstable
/metricsGETnonePrometheus-ready sync and contract observability surfacestable
/openapi.jsonGETnoneFastAPI schemainternal

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_mode
      • admitted_surface
      • role_admin_posture
      • verify_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:
{
"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
  • GET /api/v1/auth/oidc/session-contract

    • purpose:
      • current session freshness, audience, scopes, role, admin posture, and verify-path contract
  • GET /api/v1/settings/app-login

    • purpose:
      • identity summary plus admitted Mission Control app-login contract
  • admitted-surface contract:

    • surface_key
      • mission-control-v2
    • auth_mode
      • oidc_claim_projection
    • consumer_posture
      • native_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
  • 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_state
    • external_truth_state
    • external_truth
    • missing_context
    • partial_visibility
  • writeback_guard_state
  • case_lifecycle_guard
  • lifecycle_completion_guard
  • consumer_remediation_actions
  • Wave 4 hard-enforcement additions:
    • task and review-action writebacks require expected_version
    • stale or missing revision tokens return 409 with machine-readable remediation metadata
    • successful review writebacks return readback_required, expected_version, and current_version
    • lifecycle completion projection carries archive-eligible, remain-open, reopen-eligible, and forced-review-required as consumer-visible guards
  • 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#135
    • jhf-pattern#107
  • the next Plane-owned contract and implementation slice now continues in:
    • jhf-pattern#108
    • jhf-pattern#109
  • the Plane-owned enforcement wave in jhf-pattern#109 adds:
    • planning sync routes accept expected_version and reject stale writebacks with 409 conflict detail metadata
    • planning sync and discovery payloads surface workflow_state, writeback_guard_state, external_truth_state, partial_visibility, missing_context, and consumer_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
  • 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_id matches ADAPTER_SANDBOX_PROJECT_PREFIX (default sandbox-)
    • owner repo must be JaddaHelpifyr/jhf-pattern
  • supported scenarios:

    • project
    • support
    • qa
    • release
  • 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
  • handoff-aware write contract:

    • optional handoff_context for project/support scenarios
    • handoff_context.handoff_id must exist in the same project
    • handoff task/agent mismatch returns 409 and no mutation
    • response carries:
      • handoff_context
      • readback.target_summary.handoff_context
      • evidence.handoff
  • 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, query secret
      • failure status when configured secret mismatches: 403
    • ClawLedger approval callbacks:
      • routes:
        • canonical spindle pending read:
          • GET /api/approvals/jhf-spindle/pending
        • legacy clawledger approval contract:
          • POST /api/approvals/clawledger
          • GET /api/approvals/clawledger/pending
          • POST /api/approvals/clawledger/sync
          • POST /api/approvals/clawledger/{project_id}/{task_key}/decision
          • POST /api/approvals/clawledger/decision
        • compatibility aliases:
          • GET /api/v1/approvals/jhf-spindle/pending
          • GET /api/v1/approvals/clawledger/pending
      • required header when configured: X-ClawLedger-Token
      • failure status when configured secret mismatches: 401

Spindle Pending Approvals

  • canonical route:
    • GET /api/approvals/jhf-spindle/pending
  • legacy aliases:
    • GET /api/approvals/clawledger/pending
    • GET /api/v1/approvals/jhf-spindle/pending
    • GET /api/v1/approvals/clawledger/pending
  • auth:
    • header X-ClawLedger-Token when CLAWLEDGER_APPROVAL_SHARED_SECRET is configured
    • no cookie or operator session required for the inbound consumer path
  • query params:
    • project_id optional
    • limit optional, default 50, range 1-200
  • response fields per item:
    • project_id
    • task_key
    • packet_id
    • packet_name
    • packet_type
    • company
    • risk_level
    • target_doctype
    • target_name
    • lane
    • status
    • callback_url
    • created_at
    • updated_at
  • error codes:
    • 200 pending approvals returned
    • 401 shared secret configured and header mismatch
    • 422 invalid 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.md
    • docs/INTEGRATIONS.md
    • docs/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