{"api_version":"1.0","service":"sprucelab-django","file_formats":["ifc","las","laz","e57","dwg","dxf","pdf","docx","xlsx","pptx","csv","json","xml","svg","other"],"mutations_supporting_dry_run":["POST /api/types/type-mappings/bulk-update/","POST /api/types/type-definition-layers/bulk-update/","POST /api/types/claims/{id}/promote/","POST /api/types/claims/{id}/reject/","POST /api/types/claims/{id}/supersede/","PATCH /api/projects/scopes/{id}/","POST /api/automation/webhook-subscriptions/","POST /api/filters/saved/","PATCH /api/filters/saved/{id}/","POST /api/projects/scaffold/","POST /api/v2/classify/","POST /api/files/requeue/"],"access_model":{"planes":{"data":"projects, files, types, materials, issues, scopes, verification, claims, documents — open to agent tokens per capability scope","control":"scripting/code-exec, pipelines, CDE connectors, token minting, user admin — STAFF ONLY; no agent token can reach it"},"agent_token_scopes":{"read_only":"GET only, data plane","operator":"read + write, data plane","admin":"read + write + admin data ops (still NOT control plane)"},"tenancy":{"root":"per-project membership (ProjectMember)","visibility":"Every project-aware list/detail endpoint filters by membership: non-staff principals only see projects they are an active ProjectMember of. Staff see all. Cascade applies to /api/projects/, /api/models/, /api/files/, /api/files/extractions/, /api/types/types/, /api/issues/, /api/projects/scopes/, /api/projects/configs/.","writes":"Write-side authz: POST /api/files/, /api/models/upload/, /api/models/get-upload-url/, /api/models/confirm-upload/, /api/models/upload-with-metadata/ all require Project.user_can_write(user, project) = admin or editor. Viewers + non-members + anonymous principals get 403.","roles":["admin","editor","viewer"],"members_endpoint":"GET|POST /api/projects/{id}/members/ · DELETE /api/projects/{id}/members/{member_id}/","note":"A project creator (POST /api/projects/ or /scaffold/) is auto-granted ROLE_ADMIN. Tenant-scoped agent-token minting (gh #34) builds on this — a token never exceeds the minter's own project visibility."},"note":"Platform users hold agent tokens and operate only on data. Only platform staff (the owner) reach code/infra. Minting a token is itself a control-plane action — staff only."},"agent_tokens":{"platform_collection_endpoint":"GET|POST /api/agent-tokens/","platform_detail_endpoint":"DELETE /api/agent-tokens/{id}/","platform_auth":"staff Supabase user (owner)","tenant_collection_endpoint":"GET|POST /api/projects/{id}/agent-tokens/","tenant_detail_endpoint":"DELETE /api/projects/{id}/agent-tokens/{token_id}/","tenant_auth":"project admin or editor (or staff)","tenant_scope_cap":"operator (admin scope rejected on tenant mint)","company_collection_endpoint":"GET|POST /api/companies/{id}/agent-tokens/","company_detail_endpoint":"DELETE /api/companies/{id}/agent-tokens/{token_id}/","company_auth":"HUMAN company admin (mint/revoke); company admin (list)","company_scope_cap":"operator (admin scope rejected on company mint)","company_admin_capability":"company_admin=true at mint grants COMPANY MANAGEMENT (create projects, add/remove/re-role members, apply project config) for the subject company only; omit it for data operator only","scopes":["read_only","operator","admin"],"subject_kinds":["platform","company","project"],"mint_returns_raw_key_once":true,"cli":"sprucelab auth mint --name <n> --scope operator [--json]","company_cli":"sprucelab companies mint-token --company <id> [--company-admin] [--expires-days N] [--json]","note":"Agent tokens map to a synthetic approved user — no email/signup needed. Bootstrap fallback: python manage.py create_agent --name <n> --scope operator. Tenant tokens auto-narrow visibility + writes to their subject project; company tokens narrow to every project under the subject company (classified excluded); platform tokens (staff-minted) keep see-all back-compat."},"project_setup":{"eir_catalog_endpoint":"GET /api/projects/eir-catalog/","eir_presets_endpoint":"GET /api/projects/eir-presets/ (?preset=<id>, ?include_rules=false)","scaffold_endpoint":"POST /api/projects/scaffold/ (?dry_run=true)","presets":["pofin-minimum","baseline"],"default_preset":"pofin-minimum","notes":"Presets are self-contained: they bundle the required singleton rules (CRS, placement, canonical floors, IFC schema, naming, MMI/LOD, geometry rules), so a scaffolded project lands with a complete EIR. Seed your own rules via POST /api/projects/ with 'initial_eir_rules' shaped per the eir-catalog contract."},"extraction_pipelines":{"ifc":"fastapi:/api/v1/ifc/extract","pdf":"django:/api/files/{id}/extract/ → drawing+document extractors","docx":"django:/api/files/{id}/extract/ → document extractor","xlsx":"django:/api/files/{id}/extract/ → document extractor","pptx":"django:/api/files/{id}/extract/ → document extractor","dxf":"django:/api/files/{id}/extract/ → drawing extractor"},"verification":{"engine_endpoint":"GET /api/v2/verify/?project={id}&model={id}","rule_sources":["DEFAULT_RULES","ProjectConfig.config[claim_derived_rules]","ProjectConfig.config[verification][rules]"],"rule_id_prefixes":{"claim:":"derived from a promoted Claim — see /api/types/types/claim-issues/"}},"events":{"wired":["model.processed","document.processed","claim.extracted","claim.promoted","verification.complete","floor.canonical.changed"],"planned":["types.classified","quantities.extracted"],"signing":"hmac-sha256","signature_header":"X-Webhook-Signature","timestamp_header":"X-Webhook-Timestamp","event_header":"X-Webhook-Event","delivery_id_header":"X-Webhook-Delivery-Id","subscription_endpoint":"/api/automation/webhook-subscriptions/","delivery_log_endpoint":"/api/automation/webhook-deliveries/"},"embed":{"capabilities_endpoint":"/api/embed/capabilities/","instances_endpoint":"/api/embed/instances/","iframe_path":"/embed/{dashboard}?token={scoped_token}","protocol_version":1,"token_endpoints":{"collection":"/api/embed/tokens/","detail":"/api/embed/tokens/{id_or_prefix}/","refresh":"/api/embed/tokens/refresh/"},"auth":{"scheme":"Embed","header":"Authorization","query_param":"token","admin_endpoints_require_staff":true}},"cli_commands":{"auth":["sprucelab auth login [--url <URL>] [--no-browser]  (primary interactive sign-in; browser callback)","sprucelab auth register --url <URL> --token <KEY>","sprucelab auth status","sprucelab auth mint --name <n> --scope operator [--json]  (staff only)","sprucelab auth tokens [--include-inactive] [--json]","sprucelab auth revoke <id>"],"capabilities":"sprucelab capabilities [--json]","claims":["sprucelab claims list [--project] [--model] [--limit] [--json]","sprucelab claims show <id> [--json]","sprucelab claims promote <id> [--dry-run] [--json]","sprucelab claims reject <id> [--reason] [--dry-run] [--json]","sprucelab claims supersede <id> --by <newer-id> [--dry-run] [--json]","sprucelab claims conflicts <id> [--json]"],"config":["sprucelab config show","sprucelab config set <key> <value>","sprucelab config init"],"embed":["sprucelab embed pass create --project <uuid> --name <n> [--ttl] [--json]","sprucelab embed pass list [--project] [--include-revoked] [--json]","sprucelab embed pass revoke <id> [--json]","sprucelab embed pass refresh <id> [--json]"],"files":["sprucelab files list [--project] [--format] [--current-only] [--json]","sprucelab files show <id> [--json]","sprucelab files upload <path> --project <uuid> [--on-duplicate ask|use_existing|replace]","sprucelab files download <id> [--out PATH] [--overwrite]","sprucelab files reprocess <id> [--json]","sprucelab files requeue --project <uuid> | --source-file <id> [--dry-run] [--force] [--json]","sprucelab files versions <id> [--json]"],"issues":["sprucelab issues list [--project] [--status] [--assignee] [--is-open] [--source-kind] [--json]","sprucelab issues show <id> [--json]","sprucelab issues create --project <uuid> --title <t> [--severity] [--priority] [--assignee] [--json]","sprucelab issues set <id> [--status] [--assignee] [--priority] [--json]","sprucelab issues resolve <id> [--json]"],"log":"sprucelab log list [--project] [--source-file] [--category] [--json]","models":"sprucelab models list [--project-id] [--json]","projects":["sprucelab projects list [--json]","sprucelab projects show <id> [--json]","sprucelab projects create --name <name> [--number] [--owner] [--short-hand] [--description] [--preset pofin-minimum|baseline] [--dry-run] [--json]","sprucelab projects eir-catalog [--json]","sprucelab projects eir-presets [--preset <id>] [--json]","sprucelab projects mint-token <project_id> --name <n> [--scope operator|read_only] [--json]","sprucelab projects list-tokens <project_id> [--json]","sprucelab projects revoke-token <project_id> <token_id> [--json]"],"scopes":["sprucelab scopes list [--project] [--parent] [--type] [--json]","sprucelab scopes tree --project <uuid> [--json]","sprucelab scopes create --project <uuid> --name <n> [--type] [--parent] [--json]"],"types":["sprucelab types list --model <id> [--include-unused] [--json]","sprucelab types classify --model <id> (--type <id> --ns3451 <code> | --from-json <file>) [--dry-run] [--json]","sprucelab types export --model <id> --format excel|reduzer [--out PATH]"],"verify":"sprucelab verify --model <id> [--dry-run] [--json]","webhooks":"sprucelab webhooks {list,create,disable,delete,deliveries,redeliver,test}","_control_plane":"Deliberately omitted from the agent contract (staff / control-plane, not part of the headless data surface): dev, pipelines, runs, run, scripts. Version: `sprucelab --version`. Drive these via `sprucelab <group> --help` if you hold staff auth."},"field_conventions":{"owning_project":{"request_body_and_response_key":"project_id","mcp_tool_arg":"project_id","cli_flag":"--project","list_query_param":"project","note":"The project a resource belongs to is `project_id` in every request/response body and MCP tool arg. The CLI exposes it as the `--project` flag (conventional for flags). List endpoints still filter on the `?project=<uuid>` query parameter."}},"discovery":{"agent_tools_manifest":"/.well-known/agent-tools.json","llms_txt":"/llms.txt","marketing_for_agents":"https://www.sprucelab.io/agents","benchmarks":"https://www.sprucelab.io/benchmarks"},"mcp":{"package_name":"sprucelab","install":"pip install sprucelab","invocation":"sprucelab-mcp","protocol_version":"2024-11-05","transport":"stdio","tools":{"read":["capabilities","agent_tools_manifest","list_projects","list_models","list_types","list_files","list_observations","list_issues","list_scopes","list_members","list_webhooks","list_deliveries","list_tenant_tokens","eir_catalog","eir_presets","eir_rules","show_project","show_file","show_issue","extraction_log","verify_dry_run","list_claims","get_claim","claim_conflicts"],"write":["scaffold_project","classify_types","verify_model","create_issue","update_issue","issues_from_verification","resolve_issue","create_scope","add_member","remove_member","mint_tenant_token","revoke_tenant_token","eir_add_rule","eir_remove_rule","eir_apply_preset","eir_set_rules","upload_file","reprocess_file","create_webhook","disable_webhook","delete_webhook","test_webhook","redeliver","promote_claim","reject_claim","supersede_claim"]},"config_example":{"mcpServers":{"sprucelab":{"command":"sprucelab-mcp"}}}},"parser":{"ifc":"ifcfast","ifc_version_min":"0.1.0","fallback":"ifcopenshell","tier_1_speedup_vs_ifcopenshell":"25x-47x","audit_url":"https://www.sprucelab.io/benchmarks","source_repo":"https://github.com/EdvardGK/ifcfast"},"headless_coverage":{"api":82,"cli":63,"mcp":50,"total":84,"pct_api":0.98,"pct_cli":0.75,"pct_mcp":0.6},"upload_limits":{"max_file_bytes":1610612736,"global_quota_bytes":5368709120,"remaining_quota_bytes":415116909,"enforced_by":"sprucelab-early-gate + supabase-hard-cap"}}