Server definition
- Hash
- sha256:6b3a1db84ceecb6bd5bd236b983209bd51b5e5bd26c1784585305eb995075ce2
- What it is
- What a remote MCP server returned when asked what it offers: 105 tools
The blob, as servednamed by its sha256
{
"instructions": "TaScan records work as signed receipts. If the user is new to TaScan or asks how it works, call tascan_quickstart first and show them the verify link it returns: that is a real receipt a named policy verified. Completed means someone said it was done; verified means a policy checked it and signed the result. Use tascan_find to locate projects, lists and tasks by name before creating new ones.",
"tools": [
{
"description": "Add one or more subtasks to a task (bulk). Subtasks support typed responses: \"number\" for per-set data (reps, weight, distance), \"text\" for notes, \"choice\" for options, \"checkbox\" for simple steps. Set-logging example: task \"Bench Press\" with subtasks Set 1/Set 2/Set 3 each response_type \"number\" — each completed set stores its value and timestamp, giving per-set timing for progression tracking.",
"inputSchema": {
"properties": {
"subtasks": {
"description": "Array of subtasks to create",
"items": {
"properties": {
"description": {
"description": "Optional detail",
"type": "string"
},
"requires_photo": {
"description": "Require photo on completion",
"type": "boolean"
},
"response_config": {
"description": "For \"choice\": {options: [...]}. For \"number\"/\"text\": {placeholder}.",
"type": "object"
},
"response_type": {
"description": "Default checkbox. \"number\" for per-set values. \"choice\" needs response_config.options. \"link\" = the worker submits a URL. \"url\" = the worker visits a preset URL and confirms. \"file\" = the worker uploads a file.",
"enum": [
"checkbox",
"number",
"text",
"choice",
"link",
"url",
"file"
],
"type": "string"
},
"sort_order": {
"description": "Explicit position (defaults to end, in array order)",
"type": "number"
},
"title": {
"description": "Subtask title (e.g. \"Set 1\")",
"type": "string"
}
},
"required": [
"title"
],
"type": "object"
},
"type": "array"
},
"task_id": {
"description": "Parent task ID",
"type": "string"
}
},
"required": [
"task_id",
"subtasks"
],
"type": "object"
},
"name": "tascan_add_subtasks",
"outputSchema": null
},
{
"description": "Add one or more tasks to an event (task list). Supports bulk creation. IMPORTANT: Set response_type correctly — use \"text\" for info collection (names, phones, emails, notes), \"photo\" for visual verification (inspections, serial numbers, damage checks), \"checkbox\" only for simple confirmations. NOTE: To dispatch tasks to an AI agent use tascan_dispatch_to_agent instead. Writing into an agent inbox list requires the agent:dispatch permission (agent:dispatch:code for CODE:/SHELL: titles) — without it the call is refused.",
"inputSchema": {
"properties": {
"idempotency_key": {
"description": "B1: optional replay key (up to 1024 chars, no braces) sent verbatim as the Idempotency-Key header instead of a fresh one per call — a retried call with the SAME key replays the original response instead of creating the tasks twice.",
"type": "string"
},
"list_id": {
"description": "Task list (event) ID",
"type": "string"
},
"tasks": {
"description": "Array of tasks to create",
"items": {
"properties": {
"assigned_to": {
"description": "Worker to assign this task to — pass the worker UUID (validated against your org and stored as the worker's name, which is how the worker portal matches \"my tasks\"). A plain name string is also accepted as-is.",
"type": "string"
},
"description": {
"description": "Task description",
"type": "string"
},
"is_safety_checkpoint": {
"description": "Safety-critical task flag",
"type": "boolean"
},
"required_equipment": {
"description": "Equipment this task depends on (free text, e.g. \"88 lb kettlebells\")",
"type": "string"
},
"requires_photo": {
"description": "Require photo on completion",
"type": "boolean"
},
"response_config": {
"description": "Response configuration. For \"choice\": {options: [\"A\",\"B\",\"C\"]}. For \"text\": {placeholder, multiline}. For \"number\": {placeholder}. For \"date\": {label, include_text}.",
"type": "object"
},
"response_type": {
"description": "CRITICAL: \"text\" for names, phones, emails, notes, addresses, any free-form input. \"photo\" for tasks needing photographic proof (inspections, serial numbers, packed cases). \"checkbox\" ONLY for simple yes/no confirmations. \"number\" for numeric values. \"date\" for dates. \"choice\" for multiple-choice (needs response_config.options). \"link\" = the worker SUBMITS a URL (auto-verified by an http probe). \"url\" = the worker VISITS a preset URL and confirms. \"file\" = the worker uploads a file. Most info-collection tasks should be \"text\", most verification tasks should be \"photo\".",
"enum": [
"checkbox",
"photo",
"text",
"number",
"date",
"choice",
"link",
"url",
"file"
],
"type": "string"
},
"sort_order": {
"description": "Explicit sort position (defaults to end of list, in array order)",
"type": "number"
},
"subtasks": {
"description": "Subtasks created with the task. Example set logging: [{title:\"Set 1\",response_type:\"number\"},{title:\"Set 2\",response_type:\"number\"},{title:\"Set 3\",response_type:\"number\"}]",
"items": {
"properties": {
"requires_photo": {
"type": "boolean"
},
"response_config": {
"description": "Same shape as task response_config",
"type": "object"
},
"response_type": {
"description": "Typed subtask response. \"number\" for per-set values (reps/weight), \"text\" for notes, \"choice\" needs response_config.options. \"link\" = the worker submits a URL. \"url\" = the worker visits a preset URL and confirms. \"file\" = the worker uploads a file. Default checkbox.",
"enum": [
"checkbox",
"number",
"text",
"choice",
"link",
"url",
"file"
],
"type": "string"
},
"title": {
"description": "Subtask title (e.g. \"Set 1\")",
"type": "string"
}
},
"required": [
"title"
],
"type": "object"
},
"type": "array"
},
"title": {
"description": "Task title",
"type": "string"
}
},
"required": [
"title"
],
"type": "object"
},
"type": "array"
}
},
"required": [
"list_id",
"tasks"
],
"type": "object"
},
"name": "tascan_add_tasks",
"outputSchema": null
},
{
"description": "Step 1 of the Closed-Loop Autonomous Operations Protocol. Retrieves full issue context including worker info, message thread, project history, and recent similar issues. Use this data to reason about the root cause and generate a remediation plan. Also supports server-side AI analysis via POST (calls Anthropic API directly).",
"inputSchema": {
"properties": {
"issue_id": {
"description": "Issue ID to analyze",
"type": "string"
},
"server_side_ai": {
"description": "If true, the server calls Anthropic API directly for AI analysis (default: false — returns raw data for MCP client to analyze)",
"type": "boolean"
}
},
"required": [
"issue_id"
],
"type": "object"
},
"name": "tascan_analyze_issue",
"outputSchema": null
},
{
"description": "Apply a pre-built template to a task list, adding all template tasks",
"inputSchema": {
"properties": {
"list_id": {
"description": "Task list (event) ID",
"type": "string"
},
"template_slug": {
"description": "Template slug (e.g. \"conference-load-in\", \"warehouse-receiving\")",
"type": "string"
}
},
"required": [
"list_id",
"template_slug"
],
"type": "object"
},
"name": "tascan_apply_template",
"outputSchema": null
},
{
"description": "Run an AI condition assessment of an asset from a photo. The model scores 0-100 with the asset's full assessment history in context, so it reads degradation over time — returning the Condition Delta Score vs the previous assessment, defects, wear indicators, maintenance recommendations, and a degradation trajectory. Sensor-free predictive maintenance.",
"inputSchema": {
"properties": {
"asset_id": {
"description": "Asset ID (from tascan_register_asset or tascan_list_assets)",
"type": "string"
},
"photo_url": {
"description": "Public URL of the assessment photo",
"type": "string"
},
"worker_name": {
"description": "Who took the photo (optional)",
"type": "string"
}
},
"required": [
"asset_id",
"photo_url"
],
"type": "object"
},
"name": "tascan_assess_condition",
"outputSchema": null
},
{
"description": "FULL Closed-Loop Autonomous Operations Protocol in one call. Server-side AI analyzes the issue, generates remediation tasks, creates a task list, and dispatches to the worker — all without human intervention. This executes Patent Claim 7: autonomous operations from issue detection through physical-world instruction delivery.",
"inputSchema": {
"properties": {
"issue_id": {
"description": "Issue ID to auto-resolve",
"type": "string"
}
},
"required": [
"issue_id"
],
"type": "object"
},
"name": "tascan_auto_resolve",
"outputSchema": null
},
{
"description": "Cancel a scheduled text that has not been sent yet (status pending). A row already sending, sent, failed or cancelled is refused (409) — a sent text cannot be recalled.",
"inputSchema": {
"properties": {
"id": {
"description": "The scheduled_sms row id from tascan_schedule_sms / tascan_list_scheduled_sms",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"name": "tascan_cancel_scheduled_sms",
"outputSchema": null
},
{
"description": "Claim a fan-out seat task as a LOCAL subagent run (POST /runs/claim -> claim_agent_run(p_runner='local')). Only admitted when instance starts with \"<your registered agent_id>:\" -- the seat's own coord.agent_id, set when the fan-out was created (tascan_create_fanout seats[i].runner='local'). Any other instance is refused, claimed false with reason seat_not_yours -- this tool never claims a seat that is not yours, and never claims a cloud (research) seat at all (refused not_routable). Never mints a completion or a receipt by itself -- claiming only opens the run; work happens after, and tascan_finish_run is what leaves the signed receipt. Requires agent:dispatch:code. A foreign or unknown task_id is 404, never 403 (S2: another org's task never even appears to exist).",
"inputSchema": {
"properties": {
"instance": {
"description": "Your claim identity, \"<agent_id>:<anything>\" -- e.g. \"researcher-07:host-1234\". Must start with the seat's own registered agent_id or the claim is refused seat_not_yours.",
"type": "string"
},
"task_id": {
"description": "The seat task ID (UUID) -- from tascan_create_fanout's seats[] or tascan_get_fanout (view=status/report).",
"type": "string"
},
"ttl_seconds": {
"description": "Optional lease length in seconds (60-86400, default 1800). Extend it later with tascan_heartbeat_run instead of claiming a longer one up front.",
"type": "integer"
}
},
"required": [
"task_id",
"instance"
],
"type": "object"
},
"name": "tascan_claim_run",
"outputSchema": null
},
{
"description": "Complete a subtask, optionally recording a typed response_value (e.g. the weight or reps for that set). Each completion is timestamped, so consecutive set completions yield per-set durations. Returns progress including all_subtasks_complete — when true, complete the parent task with tascan_complete_task.",
"inputSchema": {
"properties": {
"notes": {
"description": "Optional notes",
"type": "string"
},
"response_value": {
"description": "Typed response value (for number/text/choice subtasks), e.g. \"165\"",
"type": "string"
},
"subtask_id": {
"description": "Subtask ID to complete",
"type": "string"
},
"worker_id": {
"description": "Worker performing the completion (optional)",
"type": "string"
}
},
"required": [
"subtask_id"
],
"type": "object"
},
"name": "tascan_complete_subtask",
"outputSchema": null
},
{
"description": "Complete an ORDINARY task on behalf of a worker. Inserts a completion record and timer event. Use this to simulate or record task completions via the API. Coordination-cycle tasks (a CODE:/REVIEW: build or review, a Decision / Question / Integrate / Parked card on a project Decisions list — tasks that carry `coord`) are refused with 403 for every key tier: builds and reviews are completed by their runner, decisions only by the human on the worker page.",
"inputSchema": {
"properties": {
"notes": {
"description": "Optional completion notes",
"type": "string"
},
"response_value": {
"description": "Response value (for text/number/choice tasks)",
"type": "string"
},
"task_id": {
"description": "Task ID to complete",
"type": "string"
},
"worker_id": {
"description": "Worker ID performing the completion",
"type": "string"
}
},
"required": [
"task_id",
"worker_id"
],
"type": "object"
},
"name": "tascan_complete_task",
"outputSchema": null
},
{
"description": "Get an asset's longitudinal condition history — score trend over time, every assessment with grade, delta, findings, and who assessed it. The per-serial-number condition ledger.",
"inputSchema": {
"properties": {
"asset_id": {
"description": "Asset ID",
"type": "string"
}
},
"required": [
"asset_id"
],
"type": "object"
},
"name": "tascan_condition_history",
"outputSchema": null
},
{
"description": "Control a running fan-out (POST /coord/fanouts/:id/control). pause holds every unclaimed seat and stops the orphan pass from re-firing them; resume releases them again; cancel supersedes every unclaimed task and closes once quiescent; close_barrier drops unsettled or named exclude_seats and forces the synth barrier now instead of waiting for more seats; retry_synth (migration 232) mints a new synth revision from the current synth's own stored inputs, correctly ordered, when every one of its failed runs is input_ref_mismatch -- refused otherwise (not_synthesizing, no_synth_task, no_failed_runs, not_input_ref_mismatch). No amend and no answer in phase 1. Every action mints a signed control-child completion FIRST, as the org's own system worker (coord_fanout_control_receipt) — never coord_dispatcher_action, so a control action can never sign into another org's Chief of Staff identity. idempotency_key replays the prior outcome (replayed:true) and applies nothing twice; a replayed resume after a later pause leaves the fan-out paused. Refused fanout_closed once the roll-up has closed. Requires agent:dispatch:code.",
"inputSchema": {
"properties": {
"action": {
"description": "pause, resume, cancel, close_barrier or retry_synth. No amend, no answer (phase 1).",
"enum": [
"pause",
"resume",
"cancel",
"close_barrier",
"retry_synth"
],
"type": "string"
},
"exclude_seats": {
"description": "close_barrier only: 1-based seat numbers to drop from the barrier instead of waiting for them to settle.",
"items": {
"type": "integer"
},
"type": "array"
},
"fanout_id": {
"description": "Fan-out id (UUID) — the T_F root.",
"type": "string"
},
"idempotency_key": {
"description": "Optional replay key (<= 200 chars). The same key returns the prior outcome (replayed:true) and applies nothing a second time.",
"type": "string"
},
"reason": {
"description": "Optional free-text reason (<= 4000 chars), recorded on the control child's completion.",
"type": "string"
}
},
"required": [
"fanout_id",
"action"
],
"type": "object"
},
"name": "tascan_control_fanout",
"outputSchema": null
},
{
"description": "Start an unattended build-review-decide cycle (protocol v0.2). Queues T1 CODE: (or SHELL:) with your build_brief on the AI Inbox and T2 REVIEW: with your review_brief, born blocked on T1. T1 (2026-09-24 throughput): kind=review_only mints T1 as CAPTURE: instead — the executor stores the bundle from the repo at HEAD without a model call and the review runs on that; dry_run=true runs the dispatch PREFLIGHT only (nothing queued) and prints every problem at once (codes title_too_long, brief_rule, brief_names_unbundled_path, artifact_over_cap, migration_as_context (tascan repo only), idempotency_replay, kind_invalid — bad kind, bad revisable_by, review_only + task_type SHELL/RESEARCH, review_only + max_questions 0), then what the API could NOT check (unchecked[]: artifact_missing_at_head always — only the executor sees the repo, and a CAPTURE naming a missing path fails with \"[artifact_missing_at_head]\" in its error; artifact_over_cap for any path without a byte count — pass artifact_bytes; idempotency_replay only if its lookup failed) and warnings[] (a build_brief naming a context file outside the bundle); a real create that the API refuses prints the same problems[] list (when the transport hands the tool only the first problem's text, the tool re-runs the preflight and prints the whole list). The local executor builds, stores the exact bytes of artifact_paths as a bundle (build_ref = sha256 over the manifest), the independent reviewer reviews THAT bundle, an approve verdict mints a Decision task for the human authority (one SMS), Approve mints an Integrate task for the deploy id. Revise verdicts spawn revisions (cap max_revisions, default 3); reject, human Reject, scope violations or exhausted revisions PARK the cycle (a Parked task with Resume with notes / Close). REQUIRES agent:dispatch:code. Duplicate protection: the same idempotency_key, or (keyless) the same briefs + paths on a live root, within 24 h is refused by the preflight as idempotency_replay (400, nothing queued, the existing root_id in the problem) and printed as DUPLICATE with that root_id; only a replay the preflight could not see (a race) comes back from the RPC as 200 created=false, printed the same way. Optional `reviews[]` attaches a multi-lens review panel (design item 14a) in place of the single OpenAI review — one review task mints per lens and every blocking lens must approve before the Decision task mints. Track with tascan_get_cycle_report (root_id). Nothing spawns a cycle on its own.",
"inputSchema": {
"properties": {
"artifact_bytes": {
"additionalProperties": {
"type": "integer"
},
"description": "Optional {path: bytes} for artifact_paths — the byte length of each file in your checkout. The API cannot read the repo, so artifact_over_cap (262144-byte reviewable cap per file) is only checked for paths you give a byte count; every other path is reported under unchecked (artifact_over_cap, unchecked_at_api) — never guessed from an earlier stored bundle. Same on dry_run and the real create.",
"type": "object"
},
"artifact_paths": {
"description": "Repo-relative paths the build binds (1-64). Exactly these files are stored as the bundle and hashed into build_ref; files the executor touches OUTSIDE them fail the scope check and park the cycle. No .., not absolute, no drive letter, no backslash.",
"items": {
"type": "string"
},
"type": "array"
},
"build_brief": {
"description": "The executor prompt (1-40000 chars). Executed verbatim by the local Claude Code runner as a CODE:/SHELL: task — write it as a complete instruction, name the files, forbid nothing the runner already forbids (deploy/commit/push are refused by its context).",
"type": "string"
},
"checkpoint_description": {
"description": "Optional description template for the Decision task; the build_ref, preview and findings summary are appended.",
"type": "string"
},
"checkpoint_title": {
"description": "Optional title template for the Decision task (default \"Decision: <title>\").",
"type": "string"
},
"dry_run": {
"description": "true = PREFLIGHT only: the API validates the whole dispatch and returns every problem at once (code, path, detail) plus the unchecked[] list (what only the executor / the RPC can decide) and warnings[] — nothing is queued, no idempotency key is consumed. Recommended before every real create. Default false.",
"type": "boolean"
},
"idempotency_key": {
"description": "Optional caller key (≤ 200 chars). The same key within 24 h is refused as idempotency_replay (nothing queued) and printed as DUPLICATE with the existing root_id — safe to retry after a lost answer.",
"type": "string"
},
"integrate_description": {
"description": "Optional description template for the Integrate task.",
"type": "string"
},
"integrate_title": {
"description": "Optional title template for the Integrate task (default \"Integrate: <title>\").",
"type": "string"
},
"kind": {
"description": "Cycle kind (default build). review_only = no model builds anything: T1 is \"CAPTURE: <title>\", a local-executor task that stores artifact_paths from the repo at HEAD as the bundle (same build_ref, size cap and scope check as a CODE build) and completes in seconds; T2 REVIEW then reviews that bundle. Use it to get an independent review of documents or of code already committed by hand. Stored as coord.kind_of_cycle on the root.",
"enum": [
"build",
"review_only"
],
"type": "string"
},
"max_cost_micro_usd": {
"description": "Per-cycle spend cap summed over every attempt, in micro-USD (default 5000000 = USD 5). A claim that could overrun it is refused (budget_exhausted).",
"type": "integer"
},
"max_questions": {
"description": "Questions a runner may ask per task before the attempt fails (default 3).",
"type": "integer"
},
"max_revisions": {
"description": "Revision cap (default 3): at most max_revisions + 1 builds and reviews.",
"type": "integer"
},
"preview_url": {
"description": "Optional https preview link shown on the Decision task.",
"type": "string"
},
"project_id": {
"description": "Working project (UUID). Its Decisions and Agent Questions lists are created on the first cycle (coord_ensure_lists). Requires the org human authority to be configured (coord_set_authority) — otherwise 403.",
"type": "string"
},
"repo": {
"description": "Which codebase on the executor the build runs in — an alias from the executor's allowlist (tascan-agent/repos.json), e.g. \"tascan\" (default), \"merchskipper\", \"inkskipper\", \"rangerlizzy\", \"cardvault\", \"take1\", \"fitcheck\", \"safegrid\", \"eternity\", \"maniacs\". artifact_paths are relative to that repo. An unknown alias is refused by the executor (repo_unknown) and the cycle parks.",
"type": "string"
},
"review_brief": {
"description": "The reviewer prompt (1-40000 chars). The reviewer reads the stored bundle (tascan_get_build / tascan_get_build_file), the task text and the filtered trail; it returns approve, revise, reject or needs_input as strict JSON bound to the build_ref. Still required even when `reviews[]` is given (kept as T2's legacy description text).",
"type": "string"
},
"reviews": {
"description": "Optional multi-lens review panel (design item 14a) instead of today's single OpenAI review_brief lens — 1-8 entries, each: {lens: slug matching ^[a-z][a-z0-9-]{0,39}$ unique per array (e.g. \"code-correctness\", \"security\", \"ui-ux\"), brief: 1-8000 chars of cycle-specific context for that lens, provider: \"openai\"|\"anthropic\"|\"gemini\", model?: 1-100 chars, blocking?: boolean (default true — at least one entry must be blocking or the whole array is refused), max_tool_calls?: integer (openai only)}. One REVIEW: task mints per lens, all blocked on T1; the Decision task mints only once every blocking lens has approved the same build. Omit for today's single OpenAI code review.",
"items": {
"properties": {
"blocking": {
"description": "Default true. At least one entry in the array must be blocking.",
"type": "boolean"
},
"brief": {
"description": "Cycle-specific context for this lens (1-8000 chars).",
"type": "string"
},
"lens": {
"description": "Slug, ^[a-z][a-z0-9-]{0,39}$, unique in the array.",
"type": "string"
},
"max_tool_calls": {
"description": "Optional, provider openai only.",
"type": "integer"
},
"model": {
"description": "Optional, 1-100 chars.",
"type": "string"
},
"provider": {
"enum": [
"openai",
"anthropic",
"gemini"
],
"type": "string"
}
},
"required": [
"lens",
"brief",
"provider"
],
"type": "object"
},
"type": "array"
},
"revisable_by": {
"description": "review_only cycles only — who fixes a revise verdict. dispatcher (default): the cycle parks on revise as today and you re-dispatch. executor: a revise spawns a revision CAPTURE task (up to max_revisions) that is born blocked on a question task \"Revise the documents, then answer to release\" addressed to you — fix the files in the repo, answer that question (tascan_post_message kind=answer), and the capture re-runs on the fixed HEAD. Build cycles always revise through the executor regardless of this field.",
"enum": [
"dispatcher",
"executor"
],
"type": "string"
},
"task_type": {
"description": "T1 prefix (default CODE). CAPTURE is never caller-settable: kind=review_only makes T1 \"CAPTURE:\" itself. With kind=review_only the value is sent as given — CODE is accepted (T1 is still CAPTURE), SHELL / RESEARCH are refused by the API as kind_invalid.",
"enum": [
"CODE",
"SHELL",
"RESEARCH"
],
"type": "string"
},
"title": {
"description": "Short human title (1-200 chars). T1 becomes \"CODE: <title>\" (\"CAPTURE: <title>\" when kind=review_only), T2 \"REVIEW: <title>\".",
"type": "string"
}
},
"required": [
"project_id",
"title",
"build_brief",
"review_brief",
"artifact_paths"
],
"type": "object"
},
"name": "tascan_create_cycle",
"outputSchema": null
},
{
"description": "Create a new event (task list) within a project. Supports team_mode (shared completions) and multi_instance (each worker gets isolated copy — great for surveys, onboarding, info collection). team_mode and multi_instance cannot both be true.",
"inputSchema": {
"properties": {
"assigned_worker_ids": {
"description": "Worker UUIDs to assign to this event. Each gets a personal tap-to-open link. Note: a worker holds one event assignment per project — assigning moves them.",
"items": {
"type": "string"
},
"type": "array"
},
"description": {
"description": "Event description",
"type": "string"
},
"multi_instance": {
"description": "Multi-instance — each worker gets isolated copy",
"type": "boolean"
},
"name": {
"description": "Event name",
"type": "string"
},
"project_id": {
"description": "Project ID",
"type": "string"
},
"team_mode": {
"description": "Team mode — shared completions",
"type": "boolean"
}
},
"required": [
"project_id",
"name"
],
"type": "object"
},
"name": "tascan_create_event",
"outputSchema": null
},
{
"description": "Create a fan-out: 1-30 seats (RESEARCH by default, or LOCAL subagent seats) plus one synthesizer under ONE cycle root T_F (POST /coord/fanouts). Zero Decision cards, zero Parked cards, zero pages per seat -- only a control action or the closing roll-up reaches a human. Requires an API key with agent:dispatch:code -- an admin session has no dispatch budget (key_required). dry_run true runs the same validation plus the ceiling/cap pre-check and returns {dry_run:true, plan_sha256, seats, problems:[]} WITHOUT consuming budget or creating anything -- a real preflight, not a real create. Otherwise consumes seats.length + 1 dispatch units BEFORE the authoritative create; a refusal only the RPC can see (cap_below_plan, fanout_open_limit, bad agent_id, reserve_floor_unset) still consumes them, by design. Fails closed fanout_ceiling_unset until the owner sets a ceiling; over_ceiling when cap exceeds it. idempotency_key replays duplicate within 24h on the same plan, else idempotency_body_mismatch. Leaves fanout_created; every seat, the synth and the roll-up leave their own signed completion. Track with tascan_get_fanout.",
"inputSchema": {
"properties": {
"breaker_k": {
"description": "Paid (non-infrastructure) seat failures before the breaker pauses the fan-out (2-5, default 2). An expired run never counts.",
"type": "integer"
},
"canary": {
"description": "How many seats release immediately; the rest stay held on T_F until the first canary settles done. Default min(2, seats.length).",
"type": "integer"
},
"cap": {
"description": "This fan-out's total micro-USD budget, synth reserve included. Refused over_ceiling if it exceeds the org's fan-out spending ceiling.",
"type": "integer"
},
"deadline_min": {
"description": "Minutes before an idle seat is dropped and the barrier re-evaluated, and before a stuck synthesizing fan-out closes deadline (10-1440, default 240).",
"type": "integer"
},
"dry_run": {
"description": "true runs the same validation plus the ceiling/cap pre-check and returns {dry_run:true, plan_sha256, seats, problems:[]} WITHOUT consuming budget or creating a fan-out -- a real preflight, not a real create.",
"type": "boolean"
},
"idempotency_key": {
"description": "Optional replay key (<= 200 chars). The same key within 24h on the same plan returns duplicate:true with the existing fanout_id; on a different plan it is refused idempotency_body_mismatch.",
"type": "string"
},
"min_ok": {
"description": "Minimum seats that must finish done before the synth barrier can close. Default ceil(seats.length / 2).",
"type": "integer"
},
"project_id": {
"description": "Working project (UUID). The fan-out root T_F is minted on its Questions list (coord_ensure_lists).",
"type": "string"
},
"seat_defaults": {
"description": "Shared defaults applied when a seat names no brief of its own.",
"properties": {
"brief": {
"description": "Default seat prompt (1-40000 chars), used by any seat that names no brief of its own.",
"type": "string"
},
"est_micro_usd": {
"description": "Positive integer micro-USD estimate per seat, used by the RPC's cap_below_plan check.",
"type": "integer"
},
"review_est_micro_usd": {
"description": "Non-negative integer micro-USD estimate per seat review. Must be > 0 when seat_review is per_seat.",
"type": "integer"
}
},
"required": [
"est_micro_usd"
],
"type": "object"
},
"seat_review": {
"description": "per_seat mints one review per seat (allowed for at most 10 seats); none skips seat review. Default per_seat for <=10 seats, none above that.",
"enum": [
"per_seat",
"none"
],
"type": "string"
},
"seats": {
"description": "1-30 seats. Each names the agent that runs it; brief/role fall back to seat_defaults when omitted.",
"items": {
"properties": {
"agent_id": {
"description": "A registered agent_registry id in this org, matching ^[a-z][a-z0-9-]{0,39}$. Never a system-* worker.",
"type": "string"
},
"brief": {
"description": "This seat's own prompt (1-40000 chars). Falls back to seat_defaults.brief when omitted -- one of the two is required.",
"type": "string"
},
"role": {
"description": "Optional label for this seat (1-100 chars), e.g. \"topic A\".",
"type": "string"
},
"runner": {
"description": "Default \"research\" (the cloud runner claims it). \"local\" names a registered local/subagent agent_id -- only that agent, claiming as itself (tascan_claim_run instance starting with \"<agent_id>:\"), can claim the seat; it is never webhook-fired.",
"enum": [
"research",
"local"
],
"type": "string"
}
},
"required": [
"agent_id"
],
"type": "object"
},
"type": "array"
},
"synth": {
"description": "The synthesizer that runs once the barrier closes, reading every done seat's stored output as DATA.",
"properties": {
"brief": {
"description": "The synthesizer's prompt (1-40000 chars).",
"type": "string"
},
"max_cost_micro_usd": {
"description": "Positive integer micro-USD reserved for the synth run; reserved out of cap up front, released back into the seat budget only at barrier close.",
"type": "integer"
}
},
"required": [
"brief",
"max_cost_micro_usd"
],
"type": "object"
},
"title": {
"description": "Short human title (1-200 chars). T_F becomes \"FANOUT: <title>\"; seats become \"RESEARCH: [seat-NN] <title>\"; the synth becomes \"RESEARCH: [synth] <title>\".",
"type": "string"
}
},
"required": [
"project_id",
"title",
"seats",
"synth",
"cap"
],
"type": "object"
},
"name": "tascan_create_fanout",
"outputSchema": null
},
{
"description": "Create a client invoice and get its shareable link. Two ways to bill: (a) pass explicit line_items, or (b) pass project_id or task_list_ids plus hourly_rate (quarter-hour billing from first→last verified completion per list) or flat_rate_per_list, and TaScan builds one line per list from VERIFIED work (\"<list> — 7/7 tasks verified · Sep 1 · 1.25h\"); lists with no completions are skipped. A single-list invoice also mints a client-facing Service Report (acknowledge → pay) and links it. Returns invoice number, totals, url, and the work it billed.",
"inputSchema": {
"properties": {
"attach_service_report": {
"description": "Mint + link a Service Report for single-list invoices (default true)",
"type": "boolean"
},
"billing": {
"description": "Billing rules for auto line items. mode: hourly (default when hourly_rate given) | day_rate | flat. Overtime/double time are computed PER WORK DAY from verified completions: hours over overtime_after_hours (default 8) bill at overtime_multiplier (1.5×), hours over double_time_after_hours (12) at double_time_multiplier (2×); set overtime:false to disable. per_diem adds one line × work days (or per_diem_days). expenses are pass-through lines.",
"properties": {
"day_rate": {
"type": "number"
},
"double_time_after_hours": {
"type": "number"
},
"double_time_multiplier": {
"type": "number"
},
"expenses": {
"items": {
"properties": {
"amount": {
"type": "number"
},
"description": {
"type": "string"
},
"quantity": {
"type": "number"
}
},
"required": [
"description",
"amount"
],
"type": "object"
},
"type": "array"
},
"flat_rate_per_list": {
"type": "number"
},
"hourly_rate": {
"type": "number"
},
"min_hours": {
"type": "number"
},
"mode": {
"enum": [
"hourly",
"day_rate",
"flat"
],
"type": "string"
},
"overtime": {
"type": "boolean"
},
"overtime_after_hours": {
"type": "number"
},
"overtime_multiplier": {
"type": "number"
},
"per_diem": {
"description": "Dollars per work day",
"type": "number"
},
"per_diem_days": {
"type": "number"
}
},
"type": "object"
},
"client_email": {
"type": "string"
},
"client_name": {
"description": "Bill-to name (person or company)",
"type": "string"
},
"client_phone": {
"type": "string"
},
"company_name": {
"description": "Your company name on the attached Service Report (defaults to the org name)",
"type": "string"
},
"due_date": {
"description": "YYYY-MM-DD (default: 30 days out)",
"type": "string"
},
"flat_rate_per_list": {
"description": "Dollars per list for auto line items (used when no hourly_rate)",
"type": "number"
},
"hourly_rate": {
"description": "Dollars per hour for auto line items",
"type": "number"
},
"line_items": {
"description": "Explicit lines instead of auto-billing",
"items": {
"properties": {
"description": {
"type": "string"
},
"quantity": {
"type": "number"
},
"unit_price": {
"type": "number"
}
},
"required": [
"description",
"unit_price"
],
"type": "object"
},
"type": "array"
},
"min_hours": {
"description": "Minimum billable hours per list (e.g. 1)",
"type": "number"
},
"notes": {
"description": "Payment terms / thank-you shown on the invoice",
"type": "string"
},
"payment_options": {
"description": "Pay-how-you-like buttons on the invoice (defaults to the org's saved handles). Keys: venmo (@handle), cashapp ($cashtag), paypal (paypal.me name), zelle (phone/email), applecash (phone), other (free text e.g. \"cash or check\"). Stripe card checkout is separate and only shows when the org has invoice_payments enabled.",
"properties": {
"applecash": {
"type": "string"
},
"cashapp": {
"type": "string"
},
"other": {
"type": "string"
},
"paypal": {
"type": "string"
},
"venmo": {
"type": "string"
},
"zelle": {
"type": "string"
}
},
"type": "object"
},
"project_id": {
"description": "Bill every list in this project (auto line items)",
"type": "string"
},
"status": {
"description": "Default sent",
"enum": [
"draft",
"sent"
],
"type": "string"
},
"task_list_ids": {
"description": "Bill just these lists (auto line items)",
"items": {
"type": "string"
},
"type": "array"
},
"tax_rate": {
"description": "Fraction, e.g. 0.0825 for 8.25%",
"type": "number"
}
},
"required": [
"client_name"
],
"type": "object"
},
"name": "tascan_create_invoice",
"outputSchema": null
},
{
"description": "Create a new TaScan project (top-level container for events)",
"inputSchema": {
"properties": {
"location": {
"description": "Project location / venue",
"type": "string"
},
"name": {
"description": "Project name",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"name": "tascan_create_project",
"outputSchema": null
},
{
"description": "Create a new worker (taskee) in the organization",
"inputSchema": {
"properties": {
"email": {
"description": "Email",
"type": "string"
},
"name": {
"description": "Worker name",
"type": "string"
},
"phone": {
"description": "Phone number",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"name": "tascan_create_worker",
"outputSchema": null
},
{
"description": "Create a geofenced work zone. Delivery zones route workers who open the project Site Gate (geo.html?project=...) to this zone's task list when GPS places them inside the radius. Set enforce_on_list=true to zone-lock the task list — workers cannot start it from outside the zone.",
"inputSchema": {
"properties": {
"alert_on_breach": {
"description": "Email + SMS the admin on containment-exit / restricted-enter (default true)",
"type": "boolean"
},
"auto_clock_in": {
"description": "Writes a shift_start when the WORKER PAGE, while open, sees the phone enter the zone; detection is pull-based, there is no background geofencing. For a background-free presence event use a gate NFC/QR scan.",
"type": "boolean"
},
"auto_clock_out": {
"description": "Writes a shift_end when the WORKER PAGE, while open, sees the phone leave the zone; detection is pull-based, there is no background geofencing. For a background-free presence event use a gate NFC/QR scan.",
"type": "boolean"
},
"description": {
"description": "Shown to workers on the Site Gate page",
"type": "string"
},
"enforce_on_list": {
"description": "Zone-lock the task list — it cannot be started from outside the radius",
"type": "boolean"
},
"enter_message": {
"description": "What the worker sees / is texted on entry (default is generated from the rule)",
"type": "string"
},
"kind": {
"description": "What the fence MEANS. work_site: expected here (auto clock-in, list on enter). hazard: enter allowed under conditions — required_ppe + photo checkpoint verified by AI vision, the OSHA row. containment: must stay inside; leaving = breach. restricted: must stay out; entering = breach. Default work_site.",
"enum": [
"work_site",
"hazard",
"containment",
"restricted"
],
"type": "string"
},
"lat": {
"description": "Zone center latitude",
"type": "number"
},
"lng": {
"description": "Zone center longitude",
"type": "number"
},
"name": {
"description": "Zone name (e.g. \"Stage Left\", \"Loading Dock\")",
"type": "string"
},
"notify_email": {
"description": "Alert recipient override — defaults to all org admins",
"type": "string"
},
"notify_on_enter": {
"description": "Email the manager when a worker enters this zone (danger areas)",
"type": "boolean"
},
"notify_on_exit": {
"description": "Email the manager when a worker leaves this zone (accountability — sign in then disappear)",
"type": "boolean"
},
"polygon": {
"description": "Polygon/rectangle zone instead of a circle: vertices as [[lat,lng], ...], at least 3. lat/lng/radius_m are then computed (centroid + bounding radius) — still pass lat/lng but they are overridden.",
"items": {
"items": {
"type": "number"
},
"type": "array"
},
"type": "array"
},
"ppe_photo_required": {
"description": "Hazard zones: pop a photo checkpoint on entry (default true when required_ppe is set)",
"type": "boolean"
},
"project_id": {
"description": "Project this zone belongs to",
"type": "string"
},
"radius_m": {
"description": "Radius in meters (default 150, min 10, max 100000)",
"type": "number"
},
"required_ppe": {
"description": "Hazard zones: PPE the worker must show at entry (pick-list so the audit reads the same words)",
"items": {
"enum": [
"hard_hat",
"safety_glasses",
"hi_vis_vest",
"gloves",
"steel_toe_boots",
"hearing_protection",
"harness",
"respirator",
"face_shield"
],
"type": "string"
},
"type": "array"
},
"sms_worker_on_enter": {
"description": "Text the worker the rule/list on entry, even if the app is closed",
"type": "boolean"
},
"sms_worker_on_exit": {
"description": "Text the worker on exit",
"type": "boolean"
},
"task_list_id": {
"description": "Task list the Site Gate routes workers to when they are inside this zone",
"type": "string"
},
"task_list_on_enter": {
"description": "Task list dispatched to the worker (in-app + SMS) when they cross into the zone",
"type": "string"
}
},
"required": [
"name",
"lat",
"lng"
],
"type": "object"
},
"name": "tascan_create_zone",
"outputSchema": null
},
{
"description": "Mint a time-limited, NARROWER child API key (POST /delegations, roadmap #11) — only read/write scopes may be requested; full, agent:dispatch, agent:dispatch:code, device:admin, delegate and webhooks:manage are always refused by name (I-6). TTL defaults to 1 hour (3600s), clamps to [60 seconds, 24 hours], and clamps further to THIS key's own expiry if it has one — a delegated key can never outlive its grantor. The child's tier is always a SUBSET of this key's own effective tier, never wider or lateral. Requires the delegate permission (owner-only to grant, requires full). The returned raw key is shown to you exactly ONCE — it is never stored server-side and cannot be retrieved again (I-10). Revoking this key (or any ancestor) cascades immediately to every key it delegated.",
"inputSchema": {
"properties": {
"resource_constraints": {
"description": "Optional free-form narrowing (e.g. project/list ids) recorded on the child key as metadata.",
"type": "object"
},
"scopes": {
"description": "Scopes to request for the child key — read and/or write only.",
"items": {
"enum": [
"read",
"write"
],
"type": "string"
},
"type": "array"
},
"ttl_seconds": {
"description": "How long the child key lives, in seconds (default 3600 = 1h; clamped to [60, 86400] and to this key's own expiry).",
"type": "number"
}
},
"required": [
"scopes"
],
"type": "object"
},
"name": "tascan_delegate_to_agent",
"outputSchema": null
},
{
"description": "Delete an event (task list) and all its tasks and completions. This action is irreversible.",
"inputSchema": {
"properties": {
"list_id": {
"description": "Task list (event) ID to delete",
"type": "string"
}
},
"required": [
"list_id"
],
"type": "object"
},
"name": "tascan_delete_event",
"outputSchema": null
},
{
"description": "Delete a project and all its events, tasks, and completions. This action is irreversible.",
"inputSchema": {
"properties": {
"project_id": {
"description": "Project ID to delete",
"type": "string"
}
},
"required": [
"project_id"
],
"type": "object"
},
"name": "tascan_delete_project",
"outputSchema": null
},
{
"description": "Delete a subtask and its completions. This action is irreversible.",
"inputSchema": {
"properties": {
"subtask_id": {
"description": "Subtask ID to delete",
"type": "string"
}
},
"required": [
"subtask_id"
],
"type": "object"
},
"name": "tascan_delete_subtask",
"outputSchema": null
},
{
"description": "Delete a specific task and its completions. This action is irreversible.",
"inputSchema": {
"properties": {
"task_id": {
"description": "Task ID to delete",
"type": "string"
}
},
"required": [
"task_id"
],
"type": "object"
},
"name": "tascan_delete_task",
"outputSchema": null
},
{
"description": "Tombstone a worker record (is_active=false). REFUSES if the worker has any task/subtask completions or payments — merge those into the real worker with tascan_merge_workers instead. Never hard-deletes.",
"inputSchema": {
"properties": {
"worker_id": {
"description": "Worker ID to delete",
"type": "string"
}
},
"required": [
"worker_id"
],
"type": "object"
},
"name": "tascan_delete_worker",
"outputSchema": null
},
{
"description": "Step 3 of the Closed-Loop Autonomous Operations Protocol. Dispatches remediation to the worker via MULTI-CHANNEL delivery: (1) issue thread message, (2) in-app notification, (3) progress feed update, (4) SMS if phone on file, (5) optional remediation task list creation. Closes the loop from digital AI analysis to physical worker execution.",
"inputSchema": {
"properties": {
"ai_agent": {
"description": "Name of the AI agent dispatching (default: TaScan AI)",
"type": "string"
},
"instruction": {
"description": "Clear, actionable instruction for the worker to execute",
"type": "string"
},
"issue_id": {
"description": "Issue ID this instruction relates to",
"type": "string"
},
"recommendation_summary": {
"description": "One-line summary for the task list description",
"type": "string"
},
"remediation_tasks": {
"description": "Optional array of tasks to create as a remediation task list. Each: { title, description, response_type, requires_photo, is_safety_checkpoint, sort_order }",
"items": {
"type": "object"
},
"type": "array"
},
"send_sms": {
"description": "Send SMS to worker (default: true if phone on file)",
"type": "boolean"
},
"worker_id": {
"description": "Target worker ID (defaults to the worker who reported the issue)",
"type": "string"
}
},
"required": [
"issue_id",
"instruction"
],
"type": "object"
},
"name": "tascan_dispatch_instruction",
"outputSchema": null
},
{
"description": "PREFERRED tool for sending work to an AI agent. Dispatches a task to the agent's inbox — picked up and executed automatically. No list ID needed. REQUIRES the agent:dispatch permission on this connection (CODE:/SHELL: tasks also require agent:dispatch:code) — reconnect and tick the agent checkbox(es) if refused. Routing is by TITLE PREFIX only: CODE: SHELL: PLAN: MCP: → local Claude Code on Mike's PC; RESEARCH: WRITE: REVIEW: → cloud; no prefix (DEFAULT) → local while the PC agent is alive, else cloud. The cloud agent refuses CODE/SHELL/PLAN/MCP. Use \"agent\" param to target a specific agent (default: claude-code-local). Use tascan_list_agents to discover available agents; track progress with tascan_get_task (its \"agent\" block).",
"inputSchema": {
"properties": {
"agent": {
"description": "Agent ID or name to dispatch to (default: claude-code-local). Use tascan_list_agents to see options. An unknown agent is an error, never a silent fallback.",
"type": "string"
},
"priority": {
"description": "Priority level (default: normal). The urgent marker is placed AFTER the routing prefix so it never breaks routing.",
"enum": [
"normal",
"urgent"
],
"type": "string"
},
"task": {
"description": "The full task text. START it with CODE: SHELL: PLAN: MCP: RESEARCH: WRITE: or REVIEW: for routing (prefix-only — nothing may precede it), or leave it unprefixed (DEFAULT). The whole text is stored in the task description; the first 140 chars become the title.",
"type": "string"
}
},
"required": [
"task"
],
"type": "object"
},
"name": "tascan_dispatch_to_agent",
"outputSchema": null
},
{
"description": "Record a chief-of-staff dispatcher action on a coordination cycle as a receipt (protocol v0.2 D6, POST /coord/cycles/:root/dispatcher-actions): hand_review_approve, hand_review_revise, park, bundle_recovery, migration_apply, deploy or decision. Mints a completed task + completion under the Chief of Staff worker and a dispatcher_action ledger event on the root. kind=deploy additionally requires evidence.deploy_id (a Netlify deploy id) and composes the same integrate-as-note every root gets with coord_record_integration when the root is authorized — one call that does both records. Requires agent:dispatch.",
"inputSchema": {
"properties": {
"evidence": {
"description": "Optional evidence object (serializes to at most 8000 chars). For kind=deploy this must include deploy_id: 24 lowercase hex, optionally prefixed deployed: and/or followed by a build-ref hex prefix.",
"type": "object"
},
"kind": {
"description": "Which dispatcher action this is.",
"enum": [
"hand_review_approve",
"hand_review_revise",
"park",
"bundle_recovery",
"migration_apply",
"deploy",
"decision"
],
"type": "string"
},
"root_id": {
"description": "The cycle root task id (tascan_list_cycles / tascan_create_cycle).",
"type": "string"
},
"summary": {
"description": "Human-readable summary (1-4000 chars) — becomes the recorded completion notes.",
"type": "string"
}
},
"required": [
"root_id",
"kind",
"summary"
],
"type": "object"
},
"name": "tascan_dispatcher_action",
"outputSchema": null
},
{
"description": "Read or author a task's evidence policy (protocol v0.2 V9b, GET|PUT /evidence/policy/:task_id — one route, two methods, so one tool). action=get evaluates the pinned policy against the evidence ledger so far: whether it is usable and satisfied, and its progress (read tier). action=set authors/updates a policy in your org's namespace when definition is given (definition.require is a non-empty array of requirement objects; definition.min_count, when set, must be an integer from 1 through definition.require.length) or, when definition is omitted, pins the task to an existing active policy_id (write tier).",
"inputSchema": {
"properties": {
"action": {
"description": "get = GET (evaluate, read tier). set = PUT (author/pin, write tier).",
"enum": [
"get",
"set"
],
"type": "string"
},
"definition": {
"description": "action=set only, optional: policy definition to create or update — require (array, required), min_count, window, any_of, allow_fallback. Omit to pin the task to the existing active policy_id instead.",
"type": "object"
},
"policy_id": {
"description": "action=set only, required: lowercase letters/digits/underscore/dot, starting with a letter, up to 80 chars, e.g. loto_v1.",
"type": "string"
},
"task_id": {
"description": "Task ID (UUID) in your organization.",
"type": "string"
},
"version": {
"description": "action=set only: optional version for a new/updated policy definition (default 1). Ignored when only pinning an existing policy.",
"type": "integer"
}
},
"required": [
"action",
"task_id"
],
"type": "object"
},
"name": "tascan_evidence_policy",
"outputSchema": null
},
{
"description": "Cross-entity search: find projects, task lists, tasks, workers, or condition assets by name in one call — with ids and parent context to disambiguate. Use this instead of walking projects→lists→tasks or guessing ids from display names.",
"inputSchema": {
"properties": {
"query": {
"description": "Search text (min 2 chars, case-insensitive substring)",
"type": "string"
},
"type": {
"description": "Optional: restrict to one entity type",
"enum": [
"project",
"list",
"task",
"worker",
"asset"
],
"type": "string"
}
},
"required": [
"query"
],
"type": "object"
},
"name": "tascan_find",
"outputSchema": null
},
{
"description": "Find candidate same-person worker records with per-signal match detail (Patent 4 §6.25(b) signals: phone reuse, name similarity, GPS pattern correlation). Turns identity fragmentation from an accidental discovery into a monitorable metric, and feeds the merge workflow its candidate list.",
"inputSchema": {
"properties": {
"include_orphans": {
"description": "Also consider org-less (orphan) worker records — off by default",
"type": "boolean"
},
"name": {
"description": "Or: search duplicates by display name",
"type": "string"
},
"threshold": {
"description": "Min confidence 0-1 (default 0.15)",
"type": "number"
},
"worker_id": {
"description": "Anchor worker to find duplicates OF (preferred — enables phone + GPS signals)",
"type": "string"
}
},
"required": [],
"type": "object"
},
"name": "tascan_find_duplicate_workers",
"outputSchema": null
},
{
"description": "Finish a claimed local run (POST /runs/:run_id/finish). outcome='completed' stores `document` (and optional `verification`) as the seat's own build artifacts under EXACTLY the artifact_paths the fan-out named for this seat, hashes them into build_ref, and finishes the run -- this mints a real task_completions row and a SIGNED TASCAN RECEIPT for your work (tascan_get_receipt), the same as any other build; `document` is your deliverable and IS what gets hashed, so send the real content, not a summary. Zero changes to coord_fanout_settle / the barrier / the roll-up -- your completion releases the next held seat and, once every seat settles, feeds the fan-out's own synthesizer and rollup exactly like a cloud research seat's would. outcome='failed' finishes the run failed with your `error` text and stores nothing. Requires agent:dispatch:code. A run outside your org, or already finished, is refused (404 / the RPC's own not_live).",
"inputSchema": {
"properties": {
"cost_micro_usd": {
"description": "Optional micro-USD cost to record against the cycle's own budget (default 0 -- a Claude Code subscription seat has no per-call API cost to report).",
"type": "integer"
},
"document": {
"description": "Required when outcome is completed. The seat's deliverable -- hashed as build_ref, stored verbatim under the seat's own artifact_paths.",
"type": "string"
},
"error": {
"description": "Required when outcome is failed -- why (up to 4000 chars).",
"type": "string"
},
"instance": {
"description": "The SAME instance string you claimed with.",
"type": "string"
},
"outcome": {
"description": "'completed' stores your document and mints a signed completion; 'failed' stores nothing.",
"enum": [
"completed",
"failed"
],
"type": "string"
},
"run_id": {
"description": "The run ID from tascan_claim_run's response.",
"type": "string"
},
"verification": {
"description": "Optional second document (a short verification/self-check note) -- stored as the seat's second artifact_path when the fan-out named two.",
"type": "string"
}
},
"required": [
"run_id",
"instance",
"outcome"
],
"type": "object"
},
"name": "tascan_finish_run",
"outputSchema": null
},
{
"description": "Generate a QR code for a task list (event) that workers can scan to access tasks",
"inputSchema": {
"properties": {
"list_id": {
"description": "Task list (event) ID",
"type": "string"
}
},
"required": [
"list_id"
],
"type": "object"
},
"name": "tascan_generate_qr",
"outputSchema": null
},
{
"description": "Mint a shareable report and get its link. Types: completion (full proof-of-work for one list: tasks, responses, subtasks, photos, GPS + place names, timing, QR pair), service (client-facing version of a list with YOUR company branding and a Client Acknowledgment button — the ack files into the list thread), project (every list in a project rolled up), evidence (compliance Evidence Pack; admin sign-in required to view). Links are stable — the same list/project returns the same link. Optionally text the link to a phone through the TaScan SMS lane.",
"inputSchema": {
"properties": {
"company_name": {
"description": "Service report branding (defaults to the org name)",
"type": "string"
},
"list_id": {
"description": "Required for completion / service",
"type": "string"
},
"message": {
"description": "Service report: a note to the client shown under the header",
"type": "string"
},
"project_id": {
"description": "Required for project / evidence",
"type": "string"
},
"send_note": {
"description": "Short intro for the text, e.g. \"Here is your report from Love Productions:\"",
"type": "string"
},
"send_to_phone": {
"description": "Text the link to this number (E.164 or 10-digit US)",
"type": "string"
},
"show_issues": {
"description": "Service report: include reported issues (default false)",
"type": "boolean"
},
"show_workers": {
"description": "Service report: show worker names (default true)",
"type": "boolean"
},
"type": {
"enum": [
"completion",
"service",
"project",
"evidence"
],
"type": "string"
}
},
"required": [
"type"
],
"type": "object"
},
"name": "tascan_generate_report",
"outputSchema": null
},
{
"description": "Read THIS credential's own per-key action budget (GET /budget): daily limits (sms, invites, payment-request cents per day and per request, dispatch, human pages) and today's spend against them. A NULL limit (or no budget row at all) means unlimited on that counter. A key can only ever see its OWN budget, never another key's (I-3, no tool or key ever reads another key's row). Read tier.",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "tascan_get_budget",
"outputSchema": null
},
{
"description": "Manifest of a stored build bundle by build_ref (protocol v0.2 build_artifacts): the exact files the executor produced for the cycle's artifact_paths, each with sha256, byte length and whether text content is stored (binary or over-cap files keep the sha only). build_ref = sha256 over the manifest, computed in the database once; the reviewer reviews THESE bytes, the human approves THIS ref, the integrate task records THIS ref. Read tier. Use tascan_get_build_file to read a file. Truncated at 12000 chars. Reading the manifest is discovery, not a read of any file.",
"inputSchema": {
"properties": {
"build_ref": {
"description": "sha256:<64 hex> (or the bare 64 hex) — from tascan_get_task (coord.build_ref / agent.runs[].build_ref) or tascan_get_cycle_report.",
"type": "string"
}
},
"required": [
"build_ref"
],
"type": "object"
},
"name": "tascan_get_build",
"outputSchema": null
},
{
"description": "Store an already-computed diff for one file of a build bundle against a base commit (protocol v0.2 item 6, POST /coord/builds/:build_ref/diff — the parser has no GET for this path; a deployed function ships no git object database, so tascan-agent/deployer.js computes the diff text with its own persistent worktree and this route only validates + stores it via coord_set_artifact_diff). build_sha256 must equal the artifact's own stored sha256 or the call is refused; storing a diff replaces that file's stored full content with the diff going forward. There is currently no REST route that reads a stored diff back (GET /builds/:build_ref and /builds/:build_ref/file do not surface it) — this tool only writes one. Requires agent:dispatch.",
"inputSchema": {
"properties": {
"base_ref": {
"description": "The commit-ish the diff was computed against (1-200 chars).",
"type": "string"
},
"base_sha256": {
"description": "Optional 64-hex sha256 of the file at base_ref.",
"type": "string"
},
"build_ref": {
"description": "sha256:<64 hex> (or the bare 64 hex) of the build the diff is about.",
"type": "string"
},
"build_sha256": {
"description": "64-hex sha256 of the file at build_ref/path — must match the stored artifact's own sha256.",
"type": "string"
},
"path": {
"description": "Repo-relative path from the build manifest (tascan_get_build).",
"type": "string"
},
"text": {
"description": "The already-computed diff text (up to 262144 characters). This tool never computes a diff itself.",
"type": "string"
},
"truncated": {
"description": "True if text is itself a truncated diff.",
"type": "boolean"
}
},
"required": [
"build_ref",
"path",
"base_ref",
"text",
"build_sha256"
],
"type": "object"
},
"name": "tascan_get_build_diff",
"outputSchema": null
},
{
"description": "Read one file from a stored build bundle by build_ref and path (protocol v0.2 build_artifacts) — the exact bytes the executor produced, not a working-tree read. Returns up to 12000 chars per call with offset/limit paging (next_offset when truncated), plus the file's sha256 and byte length. Binary or over-cap files return no content (the sha256 still binds them). Read tier; this is what the independent reviewer reads. The header lines (path, build, sha256, chars a-b of total) are the record a reviewer's read is bound to; read every chunk until the range covers the whole file.",
"inputSchema": {
"properties": {
"build_ref": {
"description": "sha256:<64 hex> (or the bare 64 hex).",
"type": "string"
},
"limit": {
"description": "Characters to return (1-12000, default 12000).",
"type": "integer"
},
"offset": {
"description": "Character offset to start from (default 0).",
"type": "integer"
},
"path": {
"description": "Repo-relative path exactly as listed by tascan_get_build.",
"type": "string"
}
},
"required": [
"build_ref",
"path"
],
"type": "object"
},
"name": "tascan_get_build_file",
"outputSchema": null
},
{
"description": "The audit report of one coordination cycle by its root task id (protocol v0.2, get_cycle_report): every step task (build, review, checkpoint, integrate, question, parked) with its revision and state, every execution attempt with runner, outcome, build_ref and usage/cost, every completion (receipt id = completion id, receipt hash), every reviewer verdict, every human decision and answer, the full trail (messages), the ledger events and the hash-chain verdict per task, plus spend against the cap. A computed summary (stage, attempts, verdicts, decisions, receipts, spend, chains_ok) comes first; pass full=true for the complete JSON (large). Read tier. This is the ONLY per-cycle notification surface: cycle steps do not e-mail or text anyone except the one checkpoint / human-question SMS.",
"inputSchema": {
"properties": {
"full": {
"description": "true = the complete report JSON (tasks, runs, completions, messages, events, bundles, chains) after the summary, capped at 12000 chars. Default: summary only.",
"type": "boolean"
},
"root_id": {
"description": "The cycle root = the T1 build task id (returned by tascan_create_cycle; a non-root cycle task returns its root_id in the error).",
"type": "string"
}
},
"required": [
"root_id"
],
"type": "object"
},
"name": "tascan_get_cycle_report",
"outputSchema": null
},
{
"description": "Get one device by id: kind, name, status, location zone, credential rotation timestamps, revocation reason, and the last 20 evidence_events ids it produced. Never returns a credential hash.",
"inputSchema": {
"properties": {
"device_id": {
"description": "Device ID",
"type": "string"
}
},
"required": [
"device_id"
],
"type": "object"
},
"name": "tascan_get_device",
"outputSchema": null
},
{
"description": "Get details of a specific event (task list) including its tasks",
"inputSchema": {
"properties": {
"list_id": {
"description": "Task list (event) ID",
"type": "string"
}
},
"required": [
"list_id"
],
"type": "object"
},
"name": "tascan_get_event",
"outputSchema": null
},
{
"description": "Read a fan-out (GET /coord/fanouts/:id?view=). view=status (default): state, seat counts, spend, cap, synth_deadline_at, poll_after_s. view=report: the full cycle report (get_cycle_report) — every seat, review and control step. view=rollup: the exact roll-up response_value plus its leaves (path, sha256, completion_id) once closed. view=verify: the server recomputes rollup_ref over the frozen leaves and returns ok / mismatches — the same check scripts/verify-fanout.js performs independently from another machine, which is the trusted proof; this view is a convenience, not a substitute. A foreign org's fanout_id answers 404, never 403, so another org's fan-out never even appears to exist. Read tier, no dispatch permission required.",
"inputSchema": {
"properties": {
"fanout_id": {
"description": "Fan-out id (UUID) — the T_F root, from tascan_create_fanout or tascan_list_cycles.",
"type": "string"
},
"view": {
"description": "status (default), report, rollup or verify.",
"enum": [
"status",
"report",
"rollup",
"verify"
],
"type": "string"
}
},
"required": [
"fanout_id"
],
"type": "object"
},
"name": "tascan_get_fanout",
"outputSchema": null
},
{
"description": "Get details of a specific project",
"inputSchema": {
"properties": {
"project_id": {
"description": "Project ID",
"type": "string"
}
},
"required": [
"project_id"
],
"type": "object"
},
"name": "tascan_get_project",
"outputSchema": null
},
{
"description": "Fetch the signed Action Receipt (Ed25519 JWS) for one completed task by completion_id (tascan_get_task -> completions[].id). Returns a readable summary (what, who, verification, evidence hashes, outcome, ledger chain) plus receipt_id/serial/kid, the compact JWS and the public verify URL. Verify offline against the JWKS or online by POSTing a JSON body whose jws field holds the compact receipt. Read outcome and verification separately: outcome completed = the executor returned and a result was recorded; verification.result = the verdict of a named policy; all-null verification with reason no_policy_run = no policy ran. Never treat outcome=completed as success without a policy verdict you trust (protocol 8.3 C11). Verifier: 6.8. profile=public returns the separately signed public export profile (protocol 6.10): it withholds the raw org, list, project, worker, run and trace ids (each a 16-hex id_hash) and storage locators, and binds to the full receipt - the form for anyone outside the org. Read tier.",
"inputSchema": {
"properties": {
"completion_id": {
"description": "task_completions.id (UUID) - from tascan_get_task -> completions[].id",
"type": "string"
},
"profile": {
"description": "full (default) = the org view with the unsigned private block; public = the separately signed public export profile: no raw org, list, project, worker, run or trace id (each is a 16-hex id_hash), no storage locators, plus a binding to the full receipt it was derived from - the form to hand to anyone outside the org",
"enum": [
"full",
"public"
],
"type": "string"
}
},
"required": [
"completion_id"
],
"type": "object"
},
"name": "tascan_get_receipt",
"outputSchema": null
},
{
"description": "Get completion report for a task list (event) including task status, completions, workers, and photos. Set include_responses to also return the actual submitted response data (numbers, text, choices) for each completed task plus a per-task photos list with fetchable signed URLs (short-lived, ~1h) for the photo evidence.",
"inputSchema": {
"properties": {
"include_responses": {
"description": "Include the actual submitted response values for each completed task (default false — keeps the payload light)",
"type": "boolean"
},
"list_id": {
"description": "Task list (event) ID",
"type": "string"
}
},
"required": [
"list_id"
],
"type": "object"
},
"name": "tascan_get_report",
"outputSchema": null
},
{
"description": "Scan accountability data. Two modes: (1) tag_id — scans of a registered NFC tag; (2) task_list_id or project_id — every QR/link page-open stamp: when the code was scanned, GPS + IP + channel (qr/nfc/sms/email/link), who the scanner turned out to be, and the scan→start delta (how long between scanning and actually identifying + starting work — the sign-in-and-vanish metric).",
"inputSchema": {
"properties": {
"limit": {
"description": "Max results (default 50, max 200)",
"type": "number"
},
"project_id": {
"description": "Project ID — page-scan mode, all lists in the project",
"type": "string"
},
"since": {
"description": "ISO timestamp — only scans after this",
"type": "string"
},
"source": {
"description": "Filter page scans by channel: qr | nfc | sms | email | link | unknown",
"type": "string"
},
"tag_id": {
"description": "NFC tag registry ID (from tascan_list_tags) — tag mode",
"type": "string"
},
"task_list_id": {
"description": "Task list ID — page-scan mode",
"type": "string"
}
},
"required": [],
"type": "object"
},
"name": "tascan_get_scan_history",
"outputSchema": null
},
{
"description": "Check delivery status of a previously sent TaScan SMS by its Twilio SID (returned by tascan_send_sms). Shows queued/sent/delivered/undelivered/failed plus carrier error codes.",
"inputSchema": {
"properties": {
"twilio_sid": {
"description": "Twilio message SID (SM...) from tascan_send_sms",
"type": "string"
}
},
"required": [
"twilio_sid"
],
"type": "object"
},
"name": "tascan_get_sms_status",
"outputSchema": null
},
{
"description": "Get details of a specific task including completions and subtasks. Each completion carries photo_url (raw storage path, stable) and photo_signed_url (short-lived fetchable URL, ~1h; null when no photo) so you can actually view the photo evidence. Tasks dispatched to an AI agent also carry an \"agent\" block (state claimed|running|completed|failed|expired|released, attempts, current run with runner/trace_id/error) — the only place agent failures are reported. A completion with status \"completed\" means the executor returned and its result was recorded (a model refusal, a wrong answer or an administrative note all \"complete\"); it does NOT mean the requested result was accepted. Acceptance is the completion evidence_check / the receipt verification.result under a named policy, and in v0.1 no policy exists for agent tasks (exact-output and rubric policies are v0.2) — check the recorded response text yourself before treating an agent completion as success (protocol §2.6, §3.2, §8.3 C11).",
"inputSchema": {
"properties": {
"task_id": {
"description": "Task ID",
"type": "string"
}
},
"required": [
"task_id"
],
"type": "object"
},
"name": "tascan_get_task",
"outputSchema": null
},
{
"description": "Read a task's trail messages (protocol v0.2 trail_messages, GET /tasks/:id/messages): question, answer, handoff and note/discussion entries, last 100, newest last (reading order). Optionally filter to a comma-separated set of kinds. Read tier. Post with tascan_post_message.",
"inputSchema": {
"properties": {
"kinds": {
"description": "Optional comma-separated kind filter, e.g. question,answer,handoff,note (discussion is stored as note; both names are accepted).",
"type": "string"
},
"task_id": {
"description": "Task ID (UUID).",
"type": "string"
}
},
"required": [
"task_id"
],
"type": "object"
},
"name": "tascan_get_task_trail",
"outputSchema": null
},
{
"description": "Read your organization's usage and quota snapshot for a billing period (GET /usage): SMS, email and AI call counts against their plan limits, the 100-receipt-per-month hard stop (used, allowance, hard_stop), the rate-limit window (60 requests per minute), and coordination-cycle spend in micro-USD for build roots created in that period. period defaults to the current UTC month (YYYY-MM). by_key additionally breaks coordination spend down per dispatch-scoped API key, refused (403 owner_required) to anything but an owner admin session -- a tsk_ key never gets it. Read tier.",
"inputSchema": {
"properties": {
"by_key": {
"description": "Break coordination spend down per dispatch-scoped API key -- owner admin session only.",
"type": "boolean"
},
"period": {
"description": "Billing period as YYYY-MM (default: current UTC month).",
"type": "string"
}
},
"type": "object"
},
"name": "tascan_get_usage",
"outputSchema": null
},
{
"description": "Ungated, plain read of one worker row: name, contact, org, points, streaks, timestamps. (tascan_get_worker_passport is the rich stats view; this is the boring lookup.)",
"inputSchema": {
"properties": {
"worker_id": {
"description": "Worker ID",
"type": "string"
}
},
"required": [
"worker_id"
],
"type": "object"
},
"name": "tascan_get_worker",
"outputSchema": null
},
{
"description": "Get a worker's verified work passport — task counts, lists worked, photos submitted, GPS-verified hours, points, streaks, and earned merit badges, all computed from real completion data (not self-reported). Includes the shareable profile URL.",
"inputSchema": {
"properties": {
"worker_id": {
"description": "Worker ID",
"type": "string"
}
},
"required": [
"worker_id"
],
"type": "object"
},
"name": "tascan_get_worker_passport",
"outputSchema": null
},
{
"description": "Extend a claimed local run's lease and mark it running (POST /runs/:run_id/heartbeat -> heartbeat_agent_run). ok false with reason not_live means the run is no longer yours -- the sweep expired it, or it was never yours to begin with -- STOP, do not finish it. Never mints a completion or a receipt. Requires agent:dispatch:code. A run outside your org is 404, never 403.",
"inputSchema": {
"properties": {
"extend_seconds": {
"description": "Optional: push expires_at out to now + this many seconds (60-86400) if that is later than the current lease -- never shortens it.",
"type": "integer"
},
"instance": {
"description": "The SAME instance string you claimed with -- a mismatch answers not_live.",
"type": "string"
},
"run_id": {
"description": "The run ID from tascan_claim_run's response.",
"type": "string"
}
},
"required": [
"run_id",
"instance"
],
"type": "object"
},
"name": "tascan_heartbeat_run",
"outputSchema": null
},
{
"description": "Invite a marketplace worker to a task list — the consented intro. TaScan texts the worker from its own number (\"<Your org> wants you for <list>. Reply YES to share your contact and get the list, or NO to pass.\"). On YES the worker appears in your org with their name + phone, receives the list link, and you get a text + a thread message. On NO or silence (7 days) you never learn who they were. Use the worker_id from tascan_search_marketplace.",
"inputSchema": {
"properties": {
"list_id": {
"description": "Task list you want them on",
"type": "string"
},
"message": {
"description": "Optional short intro prepended to the text (max 240 chars)",
"type": "string"
},
"worker_id": {
"description": "worker_id from a marketplace card",
"type": "string"
}
},
"required": [
"worker_id",
"list_id"
],
"type": "object"
},
"name": "tascan_invite_worker",
"outputSchema": null
},
{
"description": "List all registered AI agents with their capabilities, inbox IDs, and status. Like reading input labels on a video matrix — discover which agents are available and what they can do before dispatching work.",
"inputSchema": {
"properties": {},
"required": [],
"type": "object"
},
"name": "tascan_list_agents",
"outputSchema": null
},
{
"description": "List registered condition-ledger assets with their latest condition scores. Use to recover an asset_id for tascan_assess_condition or tascan_condition_history.",
"inputSchema": {
"properties": {
"project_id": {
"description": "Filter by project",
"type": "string"
}
},
"required": [],
"type": "object"
},
"name": "tascan_list_assets",
"outputSchema": null
},
{
"description": "List coordination-cycle roots in the organization (protocol v0.2, GET /coord/cycles): root id, title, status, task_type, project, build_ref, deploy_id and the T2 review id, newest first. Filter by project_id and/or status. Read tier — a reviewer's read-only key can call this too. Follow up with tascan_get_cycle_report root_id=... for the full audit trail of any row.",
"inputSchema": {
"properties": {
"limit": {
"description": "Max rows to return (default 50, max 200).",
"type": "integer"
},
"project_id": {
"description": "Optional project UUID to filter to one project's cycles.",
"type": "string"
},
"status": {
"description": "Optional cycle status to filter on (e.g. active, parked, authorized, integrated) — lowercase letters and underscores only, 1-20 chars.",
"type": "string"
}
},
"type": "object"
},
"name": "tascan_list_cycles",
"outputSchema": null
},
{
"description": "List delegated child keys (GET /delegations): this key's own direct children (id, label, scopes, active/revoked, depth, expires_at) — never the raw credential. An admin session sees every delegated key in the org. Read tier.",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "tascan_list_delegations",
"outputSchema": null
},
{
"description": "List registered devices (RFID portals, barcode guns, PLCs, cameras, robots, tools, sensors) in the organization. Filter by status (active/revoked) or kind; paginate with an opaque cursor. Never returns a credential hash.",
"inputSchema": {
"properties": {
"cursor": {
"description": "Opaque cursor from a previous response next_cursor",
"type": "string"
},
"kind": {
"description": "Filter by device kind",
"enum": [
"rfid_portal",
"barcode",
"nfc_reader",
"tool",
"plc",
"camera",
"robot",
"sensor",
"other"
],
"type": "string"
},
"limit": {
"description": "Max rows to return (1-200, default 50)",
"type": "number"
},
"status": {
"description": "Filter by device status",
"enum": [
"active",
"revoked"
],
"type": "string"
}
},
"type": "object"
},
"name": "tascan_list_devices",
"outputSchema": null
},
{
"description": "List all events (task lists) within a project",
"inputSchema": {
"properties": {
"project_id": {
"description": "Project ID",
"type": "string"
}
},
"required": [
"project_id"
],
"type": "object"
},
"name": "tascan_list_events",
"outputSchema": null
},
{
"description": "List marketplace invites you have sent and their status (pending / accepted / declined / expired / failed). Accepted invites include the worker's name and phone — that is the consent boundary; pending and declined never do.",
"inputSchema": {
"properties": {
"status": {
"enum": [
"pending",
"accepted",
"declined",
"expired",
"failed"
],
"type": "string"
}
},
"required": [],
"type": "object"
},
"name": "tascan_list_invites",
"outputSchema": null
},
{
"description": "List invoices for the org (newest first) with status, client, total, due date and share link. Filter by status (draft/sent/paid/overdue/cancelled) or project.",
"inputSchema": {
"properties": {
"project_id": {
"type": "string"
},
"status": {
"enum": [
"draft",
"sent",
"paid",
"overdue",
"cancelled"
],
"type": "string"
}
},
"required": [],
"type": "object"
},
"name": "tascan_list_invoices",
"outputSchema": null
},
{
"description": "List all issues for a task list (event). Returns open, acknowledged, and resolved issues with severity, type, and category. Use this to discover issues that need AI analysis via tascan_analyze_issue.",
"inputSchema": {
"properties": {
"list_id": {
"description": "Task list (event) ID",
"type": "string"
}
},
"required": [
"list_id"
],
"type": "object"
},
"name": "tascan_list_issues",
"outputSchema": null
},
{
"description": "List gig payments and their lifecycle status: awaiting_completion (pledged, work not verified yet), ready_to_pay (verified — pay link sent to payer), paid, canceled. Filter by task list or status.",
"inputSchema": {
"properties": {
"status": {
"description": "Filter by status",
"enum": [
"awaiting_completion",
"ready_to_pay",
"paid",
"canceled"
],
"type": "string"
},
"task_list_id": {
"description": "Filter by task list",
"type": "string"
}
},
"required": [],
"type": "object"
},
"name": "tascan_list_payments",
"outputSchema": null
},
{
"description": "List all TaScan projects in the organization",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "tascan_list_projects",
"outputSchema": null
},
{
"description": "List existing report links for a list or project (completion / service / project / evidence), newest first, with client acknowledgment status for service reports.",
"inputSchema": {
"properties": {
"list_id": {
"type": "string"
},
"project_id": {
"type": "string"
}
},
"required": [],
"type": "object"
},
"name": "tascan_list_reports",
"outputSchema": null
},
{
"description": "List your org's scheduled texts (default: pending + sending, soonest first; status=sent|failed|cancelled to see history). Each row shows send_at, status, attempts, the Twilio sid once sent, and the last error for a failed row.",
"inputSchema": {
"properties": {
"status": {
"description": "Filter by status (default pending + sending)",
"enum": [
"pending",
"sending",
"sent",
"failed",
"cancelled"
],
"type": "string"
}
},
"type": "object"
},
"name": "tascan_list_scheduled_sms",
"outputSchema": null
},
{
"description": "List the subtasks of a task, including completion state, stored response values, and completion timestamps (per-set timing).",
"inputSchema": {
"properties": {
"task_id": {
"description": "Parent task ID",
"type": "string"
}
},
"required": [
"task_id"
],
"type": "object"
},
"name": "tascan_list_subtasks",
"outputSchema": null
},
{
"description": "List all registered NFC tags in the organization with their linked projects/task lists and scan counts",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "tascan_list_tags",
"outputSchema": null
},
{
"description": "List all tasks in an event (task list)",
"inputSchema": {
"properties": {
"list_id": {
"description": "Task list (event) ID",
"type": "string"
}
},
"required": [
"list_id"
],
"type": "object"
},
"name": "tascan_list_tasks",
"outputSchema": null
},
{
"description": "List available task templates (built-in and saved)",
"inputSchema": {
"properties": {
"category": {
"description": "Filter by category (e.g. \"live-events\", \"hospitality\", \"logistics\")",
"type": "string"
}
},
"type": "object"
},
"name": "tascan_list_templates",
"outputSchema": null
},
{
"description": "Read a task completion's verification verdicts and job queue (Verification Layer V2, GET /completions/:completion_id/verifications): completion_verifications rows (state, method, verifier, policy, confidence, finding) plus verification_jobs rows (state, attempts, last_error, result). Read tier.",
"inputSchema": {
"properties": {
"completion_id": {
"description": "task_completions.id (UUID) — from tascan_get_task -> completions[].id.",
"type": "string"
}
},
"required": [
"completion_id"
],
"type": "object"
},
"name": "tascan_list_verifications",
"outputSchema": null
},
{
"description": "List workers (taskees) in the organization. Supports filtering by name/email/phone substring, contact-info presence, and last-activity date. Each row includes completion_count (total task completions).",
"inputSchema": {
"properties": {
"active_since": {
"description": "ISO date/datetime — only workers with last_active_at on/after this",
"type": "string"
},
"has_email": {
"description": "true/false — same for email",
"type": "boolean"
},
"has_phone": {
"description": "true = only workers with a phone on file; false = only without",
"type": "boolean"
},
"include_inactive": {
"description": "true = also include inactive workers (e.g. tombstones left by a merge or delete) — useful for auditing right after tascan_merge_workers / tascan_delete_worker",
"type": "boolean"
},
"query": {
"description": "Substring match on name, email, or phone",
"type": "string"
}
},
"type": "object"
},
"name": "tascan_list_workers",
"outputSchema": null
},
{
"description": "List geofenced work zones, optionally filtered by project. Shows center, radius, routing target, and zone-lock status.",
"inputSchema": {
"properties": {
"project_id": {
"description": "Filter by project",
"type": "string"
}
},
"required": [],
"type": "object"
},
"name": "tascan_list_zones",
"outputSchema": null
},
{
"description": "Merge duplicate worker records into one canonical identity (Patent 4 identity consolidation). Reassigns every reference (completions, timer events, points, payments, rosters — 31 columns across 31 tables), backfills missing phone/email on the primary, sums points, and tombstones the duplicates (merged_into + is_active=false — NEVER hard-deletes). ALWAYS run with dry_run=true first and show Mike the counts; pass dry_run=false only after explicit confirmation.",
"inputSchema": {
"properties": {
"dry_run": {
"description": "true (default) = report reassignment counts only, change nothing. false = execute atomically.",
"type": "boolean"
},
"duplicate_worker_ids": {
"description": "Worker IDs to fold into the primary (max 20)",
"items": {
"type": "string"
},
"type": "array"
},
"primary_worker_id": {
"description": "The canonical worker that survives (usually the one with a phone)",
"type": "string"
}
},
"required": [
"primary_worker_id",
"duplicate_worker_ids"
],
"type": "object"
},
"name": "tascan_merge_workers",
"outputSchema": null
},
{
"description": "Read organization-wide analytics: view org (GET /analytics/org, the get_org_analytics rollup) or view resolutions (GET /analytics/resolutions, paginated AI issue-resolution history, filterable by severity, category, and pattern-detected). Read tier.",
"inputSchema": {
"properties": {
"category": {
"description": "resolutions only: filter by issue_category.",
"type": "string"
},
"limit": {
"description": "resolutions only: page size (default 50, max 200).",
"type": "integer"
},
"offset": {
"description": "resolutions only: page offset.",
"type": "integer"
},
"pattern": {
"description": "resolutions only: true to filter to pattern_detected rows only.",
"type": "boolean"
},
"severity": {
"description": "resolutions only: filter by classification_severity.",
"type": "string"
},
"view": {
"description": "Which analytics surface to read.",
"enum": [
"org",
"resolutions"
],
"type": "string"
}
},
"required": [
"view"
],
"type": "object"
},
"name": "tascan_org_analytics",
"outputSchema": null
},
{
"description": "Post one evidence event into the evidence ledger (protocol v0.2 V9a, POST /evidence): an actor did an action to an object at a point in time, optionally with a location and provenance. idempotency_key is required — the same (org, idempotency_key) always returns the same row, never a second insert. Optionally correlate the event to a task or task list. Write tier; a device credential (structurally different from an API key) is not reachable through this MCP connection, so device_id is never set here.",
"inputSchema": {
"properties": {
"action": {
"description": "What happened, e.g. inspected, scanned, calibrated.",
"type": "string"
},
"actor": {
"description": "Who did it.",
"properties": {
"id": {
"description": "The actor's id.",
"type": "string"
},
"kind": {
"description": "worker requires an active, unmerged worker id in your organization; agent/device ids are recorded as given.",
"enum": [
"worker",
"agent",
"device"
],
"type": "string"
}
},
"required": [
"kind",
"id"
],
"type": "object"
},
"correlation": {
"description": "Optional correlation hint.",
"properties": {
"task_id": {
"description": "A task UUID in your organization to correlate this evidence to.",
"type": "string"
},
"task_list_id": {
"description": "A task list UUID in your organization to correlate this evidence to (used when task_id is absent or does not resolve).",
"type": "string"
}
},
"type": "object"
},
"idempotency_key": {
"description": "Required, 1-200 chars. The same key on the same org replays the same stored row.",
"type": "string"
},
"location": {
"description": "Optional location.",
"properties": {
"lat": {
"type": "number"
},
"lng": {
"type": "number"
},
"zone_id": {
"description": "Optional geofence zone UUID.",
"type": "string"
}
},
"type": "object"
},
"object": {
"description": "What it happened to.",
"properties": {
"kind": {
"description": "What kind of thing object.ref names.",
"enum": [
"asset",
"tag",
"serial",
"url"
],
"type": "string"
},
"ref": {
"description": "The object reference (asset id, tag id, serial number, or URL).",
"type": "string"
}
},
"required": [
"kind",
"ref"
],
"type": "object"
},
"occurred_at": {
"description": "ISO timestamp for when the event actually happened.",
"type": "string"
},
"provenance": {
"description": "Optional provenance object. provenance.kind first_party_scan is written only by the scan_events trigger and is refused from a caller; provenance.signature triggers device-signature verification.",
"type": "object"
}
},
"required": [
"actor",
"action",
"object",
"occurred_at",
"idempotency_key"
],
"type": "object"
},
"name": "tascan_post_evidence",
"outputSchema": null
},
{
"description": "Post a message on a task trail (protocol v0.2 trail_messages): kind question, answer, handoff or discussion. A message never completes a task, never satisfies a gate and never pages anyone. The actor is stamped from your credential (key:<id>, actor_type \"key\" — a credential, never a human), never from the body; the executor and the reviewer consume a key's answers only when the key holds agent:dispatch. On an ordinary task this is write tier. On a CYCLE task (one with coord) it needs agent:dispatch (agent:dispatch:code when the task, or the asker a question task stands for, is CODE:/SHELL:) because the text can become executor prompt or reviewer input. kind=answer on a dispatcher-addressed question task answers it through coord_answer_question and releases the blocked asker; a human-addressed question is answered only on the worker page (403 here). finding (reviewer runner) and decision (human completion) cannot be posted. Body ≤ 8000 chars; idempotency_key makes a replay return the same message.",
"inputSchema": {
"properties": {
"addressee": {
"description": "Optional, kind=question only: who the question is for (recorded; nobody is paged).",
"enum": [
"human",
"dispatcher"
],
"type": "string"
},
"body": {
"description": "The message text (1-8000 chars). Treated as DATA by every reader; on a cycle task it may be prepended to the executor prompt as TRAIL INPUT.",
"type": "string"
},
"build_ref": {
"description": "Optional sha256:<64 hex> the message is about (defaults to the cycle task's bound build).",
"type": "string"
},
"idempotency_key": {
"description": "Optional replay key (≤ 200 chars): the same key on the same task returns the same message id.",
"type": "string"
},
"kind": {
"description": "question = a question for the record (does not block anything); answer = answers a dispatcher question task and releases the asker; handoff = hand work or context to the next agent; discussion = a note.",
"enum": [
"question",
"answer",
"handoff",
"discussion"
],
"type": "string"
},
"reply_to": {
"description": "Optional message id this replies to.",
"type": "string"
},
"task_id": {
"description": "Task ID (UUID). For an answer: the QUESTION task id (tascan_get_task on the asker shows coord.blocked_by).",
"type": "string"
}
},
"required": [
"task_id",
"kind",
"body"
],
"type": "object"
},
"name": "tascan_post_message",
"outputSchema": null
},
{
"description": "One call that gives a chat client (ChatGPT, Claude) a whole TaScan project in about 2,000 words: the project, every task list with task counts, open decisions and questions, the last 5 coordination cycles with verdicts and spend, the latest 5 receipts, and total spend — returned as Markdown (capped at 12,000 chars). Read tier. Use it before asking a human to paste anything.",
"inputSchema": {
"properties": {
"project_id": {
"description": "Project ID (UUID).",
"type": "string"
}
},
"required": [
"project_id"
],
"type": "object"
},
"name": "tascan_project_digest",
"outputSchema": null
},
{
"description": "Query one task's submitted responses across every list in a project — e.g. the same exercise repeated across many workout lists returns one chronological progression series instead of N report lookups. Match by task title pattern or exact task ID. Subtask completions interleave into the same series labeled 'Task › Subtask' (e.g. per-set values Set 1/2/3 with their own timestamps), so set-level progression chains across lists automatically.",
"inputSchema": {
"properties": {
"limit": {
"description": "Max responses to return (default 200, max 500)",
"type": "number"
},
"project_id": {
"description": "Project ID",
"type": "string"
},
"task": {
"description": "Task title pattern (case-insensitive substring) or exact task ID",
"type": "string"
}
},
"required": [
"project_id",
"task"
],
"type": "object"
},
"name": "tascan_query_responses",
"outputSchema": null
},
{
"description": "One action to a genuinely verified receipt (POST /quickstart). Under your org it reuses-or-creates the project \"TaScan Quickstart\", its list \"Quickstart\" and the worker \"Quickstart executor\", adds a NEW task \"Reply with the exact text: <expected>\", completes it with your key, has the named policy quickstart_exact_output v1 compare the response to the expected text (verified or refuted, signed into the receipt), and publishes the receipt's public profile. expected defaults to \"VERIFIED\" (max 200 chars); response defaults to expected — pass a different response to see a refuted receipt. Returns the receipt URL and the public verify URL. Write tier.",
"inputSchema": {
"properties": {
"expected": {
"description": "The exact text the task asks for (default \"VERIFIED\", max 200 chars).",
"type": "string"
},
"response": {
"description": "The response to submit (default: the expected text). A different value is refuted.",
"type": "string"
}
},
"type": "object"
},
"name": "tascan_quickstart",
"outputSchema": null
},
{
"description": "Step 2 of the Closed-Loop Autonomous Operations Protocol. Post an AI-generated recommendation to an issue thread. Accepts both a text recommendation and an optional structured_recommendation object with task definitions for auto-dispatch. The recommendation is persisted in the AI audit trail.",
"inputSchema": {
"properties": {
"ai_agent": {
"description": "Name of the AI agent posting (default: TaScan AI)",
"type": "string"
},
"issue_id": {
"description": "Issue ID to recommend a fix for",
"type": "string"
},
"recommendation": {
"description": "The AI-generated recommendation text (clear, actionable instructions)",
"type": "string"
},
"structured_recommendation": {
"description": "Optional structured recommendation with tasks for auto-dispatch. Format: { recommendation_summary, confidence_score, tasks: [{ title, description, response_type, requires_photo, is_safety_checkpoint, sort_order }], estimated_duration_minutes, required_responder_role }",
"type": "object"
}
},
"required": [
"issue_id",
"recommendation"
],
"type": "object"
},
"name": "tascan_recommend_fix",
"outputSchema": null
},
{
"description": "D4: the dispatcher records the Netlify deploy id for an authorized cycle — Integrate cards stop landing on Mike for something a key can prove instead (protocol v0.2, migration 181, coord_record_integration). Requires agent:dispatch. The root must be `authorized` (its checkpoint already Approved) with an open Integrate task; deploy_id must be a real Netlify deploy id — 24 lowercase hex, optionally \"deployed:<id>\" and/or a trailing build-ref hex prefix (\"Deploy\" and anything else is refused, bad_deploy_id). On success the root flips to `integrated`, the existing \"Integrated: deploy …\" trail note is posted, and the completion is stamped with your key as the actor (source api:key:<id>) — never as a human on the page. Idempotent: replaying the SAME deploy_id after the root is already integrated returns the same completion (replayed:true); a DIFFERENT deploy_id after integration is refused (409) without changing anything. A human may still complete the Integrate card on the worker page as an ops fallback, but only with a real deploy id too.",
"inputSchema": {
"properties": {
"deploy_id": {
"description": "The Netlify deploy id: 24 lowercase hex, optionally prefixed \"deployed:\" and/or followed by a space and a ≥12-hex prefix of the build_ref.",
"type": "string"
},
"note": {
"description": "Optional note (≤ 2000 chars) recorded alongside the completion — e.g. what changed in this deploy.",
"type": "string"
},
"root_id": {
"description": "The cycle root = the T1 build task id (tascan_get_cycle_report / tascan_create_cycle). Must currently be authorized (checkpoint Approved, Integrate task open).",
"type": "string"
}
},
"required": [
"root_id",
"deploy_id"
],
"type": "object"
},
"name": "tascan_record_integration",
"outputSchema": null
},
{
"description": "Register a new AI agent in the agent registry. The agent will appear in tascan_list_agents and can receive dispatched tasks. Self-registration for AI agents joining the TaScan network. REQUIRES the agent:dispatch permission (defining a dispatch target is a dispatch permission); inbox_id must be a task list (event) in your organization.",
"inputSchema": {
"properties": {
"capabilities": {
"description": "Task type prefixes this agent handles (e.g. [\"RESEARCH\", \"WRITE\"])",
"items": {
"type": "string"
},
"type": "array"
},
"description": {
"description": "What this agent does",
"type": "string"
},
"id": {
"description": "Unique agent ID (e.g. \"my-agent-1\")",
"type": "string"
},
"inbox_id": {
"description": "Task list ID this agent monitors for new tasks",
"type": "string"
},
"location": {
"description": "Where the agent runs (e.g. \"AWS us-east-1\")",
"type": "string"
},
"model": {
"description": "Model powering this agent (e.g. \"claude-sonnet-4-6\")",
"type": "string"
},
"name": {
"description": "Display name (e.g. \"Research Bot\")",
"type": "string"
},
"type": {
"description": "Agent type",
"enum": [
"local",
"cloud",
"hybrid"
],
"type": "string"
},
"worker_id": {
"description": "TaScan worker ID for this agent",
"type": "string"
}
},
"required": [
"id",
"name",
"type",
"inbox_id",
"capabilities"
],
"type": "object"
},
"name": "tascan_register_agent",
"outputSchema": null
},
{
"description": "Register a physical asset (equipment, structure, vehicle, machine) in the condition ledger so it can be assessed over time. Each asset gets a longitudinal condition history with AI scoring and degradation trajectory.",
"inputSchema": {
"properties": {
"asset_type": {
"description": "Type (e.g. \"LED processor\", \"forklift\", \"scaffold\")",
"type": "string"
},
"description": {
"description": "Context the AI assessor should know",
"type": "string"
},
"location_description": {
"type": "string"
},
"name": {
"description": "Asset name (e.g. \"LED Wall Processor #3\")",
"type": "string"
},
"project_id": {
"type": "string"
},
"serial_number": {
"description": "Serial number or asset tag (unique per org)",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"name": "tascan_register_asset",
"outputSchema": null
},
{
"description": "Register a physical NFC tag to a project, task list, or specific task. When someone taps the tag, TaScan routes them to the linked resource. Tags use NTAG215 chips and are programmed with NFC Tools Pro.",
"inputSchema": {
"properties": {
"location_description": {
"description": "Physical location of the tag",
"type": "string"
},
"project_id": {
"description": "Project ID",
"type": "string"
},
"tag_hardware_id": {
"description": "NFC tag hardware serial number (e.g., \"04:CB:6C:51:CE:2A:81\")",
"type": "string"
},
"tag_name": {
"description": "Friendly name (e.g., \"Ballroom A Door\", \"Breaker Panel 3\")",
"type": "string"
},
"target_type": {
"description": "What this tag points to",
"enum": [
"project",
"task_list",
"task"
],
"type": "string"
},
"task_id": {
"description": "Task ID (required for task targets)",
"type": "string"
},
"task_list_id": {
"description": "Task list ID (required for task_list/task targets)",
"type": "string"
}
},
"required": [
"tag_hardware_id",
"tag_name",
"target_type"
],
"type": "object"
},
"name": "tascan_register_tag",
"outputSchema": null
},
{
"description": "Reply to a task list WITH a task list — the two-way tasking primitive. Creates a new list linked into the parent's thread, aimed back at whoever sent the original (e.g. \"Grant access — pick a window\" with response_type date, or an info request with response_type text). The org gets pinged; the thread shows in both the worker portal and Simple Mode. Use tascan_get_thread-style follow-up via tascan_list_projects/tascan_get_report to read answers.",
"inputSchema": {
"properties": {
"author_name": {
"description": "Who is replying (shown in the thread)",
"type": "string"
},
"parent_list_id": {
"description": "The list being replied to",
"type": "string"
},
"tasks": {
"description": "Items the recipient answers — each becomes a typed task",
"items": {
"properties": {
"description": {
"type": "string"
},
"response_config": {
"type": "object"
},
"response_type": {
"description": "\"date\" for scheduling windows, \"text\" for info requests, \"choice\" needs response_config.options. \"link\" = the worker submits a URL. \"url\" = the worker visits a preset URL and confirms. \"file\" = the worker uploads a file.",
"enum": [
"checkbox",
"text",
"number",
"date",
"choice",
"photo",
"link",
"url",
"file"
],
"type": "string"
},
"title": {
"type": "string"
}
},
"required": [
"title"
],
"type": "object"
},
"type": "array"
},
"title": {
"description": "Reply list title (e.g. \"Before I can start...\")",
"type": "string"
}
},
"required": [
"parent_list_id",
"title",
"tasks"
],
"type": "object"
},
"name": "tascan_reply_with_list",
"outputSchema": null
},
{
"description": "Pledge a payment on a task list: when the list is verified complete (every task done + photo evidence on photo-required tasks), the payer automatically receives a Stripe pay link that routes the money DIRECTLY to the worker (0% TaScan fee). No money moves and no card is stored at pledge time. The worker must have completed payout onboarding (Get Paid on their profile).",
"inputSchema": {
"properties": {
"amount_cents": {
"description": "Amount in cents ($1 min, $10,000 max)",
"type": "number"
},
"idempotency_key": {
"description": "B1: optional replay key (up to 1024 chars, no braces) sent verbatim as the Idempotency-Key header instead of a fresh one per call — a retried call with the SAME key replays the original pledge instead of creating a second one.",
"type": "string"
},
"memo": {
"description": "What the payment is for (shown to the payer)",
"type": "string"
},
"payer_email": {
"description": "Who pays — receives the pay link on verification",
"type": "string"
},
"payer_name": {
"type": "string"
},
"task_list_id": {
"description": "Task list the payment is tied to",
"type": "string"
},
"worker_id": {
"description": "Worker who gets paid",
"type": "string"
}
},
"required": [
"task_list_id",
"worker_id",
"amount_cents",
"payer_email"
],
"type": "object"
},
"name": "tascan_request_payment",
"outputSchema": null
},
{
"description": "Enqueue an autonomous verification job for a task completion (Verification Layer V2 + V7 doc_check, POST /completions/:completion_id/verification-jobs): http_probe checks a URL (params url, and optionally expect_status, expect_content_type, expect_sha256), doc_check runs a named policy against params.url and params.policy_id. Read the result with tascan_list_verifications once the job runs. Write tier.",
"inputSchema": {
"properties": {
"check_type": {
"description": "Which autonomous check to run.",
"enum": [
"http_probe",
"doc_check"
],
"type": "string"
},
"completion_id": {
"description": "task_completions.id (UUID) — from tascan_get_task -> completions[].id.",
"type": "string"
},
"idempotency_key": {
"description": "Optional replay key (up to 200 chars).",
"type": "string"
},
"params": {
"description": "For http_probe: url, and optionally expect_status, expect_content_type, expect_sha256. For doc_check: url and policy_id, where policy_id names an active doc_check policy.",
"type": "object"
},
"run_at": {
"description": "Optional ISO timestamp to schedule the job for (default now).",
"type": "string"
}
},
"required": [
"completion_id",
"check_type",
"params"
],
"type": "object"
},
"name": "tascan_request_verification",
"outputSchema": null
},
{
"description": "Revoke a delegated child key immediately (DELETE /delegations/:key_id) — self-revoke, revoke by an ancestor key, or by an admin session of the org; any other caller is refused. Revoking cascades to every key IT delegated, in turn (the database trigger, not application code). Idempotent: revoking an already-revoked key reports already_revoked, no error.",
"inputSchema": {
"properties": {
"key_id": {
"description": "The delegated key id to revoke (from tascan_list_delegations)",
"type": "string"
}
},
"required": [
"key_id"
],
"type": "object"
},
"name": "tascan_revoke_delegation",
"outputSchema": null
},
{
"description": "Revoke a device credential immediately — the kill switch for a lost, stolen, or decommissioned device (RFID portal, barcode gun, PLC, camera, robot, tool, sensor). Its next evidence post is refused. Idempotent: revoking an already-revoked device reports already_revoked and mints no second receipt. Requires the device:admin permission (owner-only, needs full, never reachable through OAuth).",
"inputSchema": {
"properties": {
"device_id": {
"description": "Device ID to revoke",
"type": "string"
},
"reason": {
"description": "Why this device is being revoked (up to 500 characters)",
"type": "string"
}
},
"required": [
"device_id"
],
"type": "object"
},
"name": "tascan_revoke_device",
"outputSchema": null
},
{
"description": "Schedule a transactional TaScan SMS for a future time (up to 90 days out): the text is sent by TaScan's own scheduler (every 5 minutes) through the same guarded lane as tascan_send_sms — recipient must be a worker of your org or a phone the org already knows, STOP opt-outs honoured, burst limits and the SMS quota apply, the \"TaScan:\" prefix is added, and a list_id appends a tap-to-open checklist link. Use this for reminders (e.g. \"log your out time\" each show night) — nothing outside TaScan needs to stay awake. Returns the scheduled row id; cancel with tascan_cancel_scheduled_sms while it is still pending. The same idempotency_key within an org returns the existing row instead of a duplicate.",
"inputSchema": {
"properties": {
"idempotency_key": {
"description": "Optional caller key (≤ 200 chars) — replays return the existing scheduled row",
"type": "string"
},
"include_link": {
"description": "Append the list link (default true when list_id is given)",
"type": "boolean"
},
"list_id": {
"description": "Optional task list ID — appends the tap-to-open checklist link",
"type": "string"
},
"message": {
"description": "Message text (1-400 chars, links stripped). Transactional and work-related only.",
"type": "string"
},
"phone": {
"description": "Raw phone (E.164) — must already belong to a worker or roster entry of your org",
"type": "string"
},
"send_at": {
"description": "When to send — ISO 8601 with a timezone offset, e.g. \"2026-09-25T18:30:00-07:00\" (Las Vegas is -07:00 in September). Delivery happens on the next 5-minute tick at or after this time.",
"type": "string"
},
"worker_id": {
"description": "Worker ID — texts their phone on file (preferred over raw phone)",
"type": "string"
}
},
"required": [
"send_at",
"message"
],
"type": "object"
},
"name": "tascan_schedule_sms",
"outputSchema": null
},
{
"description": "Search the cross-org Worker Marketplace: workers who opted in (discoverable=true on their passport), ranked by passkey trust tier + verified completion volume. Skills are AI-inferred from REAL completed work, not resumes — each carries a verified_task_count and a civilian_equivalent job title. Returns sanitized public cards only (first name + last initial, skills, stats, passport URL) — never phone, email, or org membership.",
"inputSchema": {
"properties": {
"available": {
"description": "Only workers who marked themselves available on their passport",
"type": "boolean"
},
"city": {
"description": "Filter by the worker's opt-in home city, e.g. \"Las Vegas\"",
"type": "string"
},
"limit": {
"description": "Max cards (default 25, max 50)",
"type": "number"
},
"min_completions": {
"description": "Only workers with at least this many verified completions",
"type": "number"
},
"q": {
"description": "Skill, category, name, or civilian job title — e.g. \"forklift\", \"LED wall\", \"AV technician\"",
"type": "string"
}
},
"required": [],
"type": "object"
},
"name": "tascan_search_marketplace",
"outputSchema": null
},
{
"description": "Send a transactional TaScan SMS text to a worker (by worker_id, using their phone on file) or to a raw phone number. Optionally attach a task list — the recipient gets a tap-to-open checklist link. Sends from TaScan's carrier-registered A2P number (or the org's own Twilio if BYOK). Counts against the org's monthly SMS quota unless BYOK. Messages are auto-prefixed with \"TaScan:\" per carrier registration; transactional/work-related content only, no marketing.",
"inputSchema": {
"properties": {
"idempotency_key": {
"description": "B1: optional replay key (up to 1024 chars, no braces) sent verbatim as the Idempotency-Key header instead of a fresh one per call — a retried call with the SAME key replays the original response instead of sending a second text.",
"type": "string"
},
"include_link": {
"description": "When a list_id is given, append the tap-to-open link to the SMS body (default true). Set false to send the message text alone — the link is still returned for you to share another way.",
"type": "boolean"
},
"list_id": {
"description": "Optional task list ID — appends a tap-to-open worker checklist link",
"type": "string"
},
"message": {
"description": "Message text. Transactional and work-related only.",
"type": "string"
},
"phone": {
"description": "Raw phone number (e.g. \"+17025551234\") — used when no worker_id given",
"type": "string"
},
"worker_id": {
"description": "Worker ID — sends to their phone on file (preferred over raw phone)",
"type": "string"
}
},
"required": [
"message"
],
"type": "object"
},
"name": "tascan_send_sms",
"outputSchema": null
},
{
"description": "Send a branded TaScan task notification email via SendGrid. Can notify anyone about a specific task list or task. Includes QR code, task summary, and \"Open in TaScan\" button.",
"inputSchema": {
"properties": {
"include_qr": {
"description": "Include QR code for the task list in the email (default: true)",
"type": "boolean"
},
"list_id": {
"description": "Task list (event) ID",
"type": "string"
},
"message": {
"description": "Optional custom message to include in the email body",
"type": "string"
},
"subject": {
"description": "Custom email subject (defaults to auto-generated)",
"type": "string"
},
"task_id": {
"description": "Optional specific task ID to highlight",
"type": "string"
},
"to_email": {
"description": "Recipient email address",
"type": "string"
},
"to_name": {
"description": "Recipient display name",
"type": "string"
}
},
"required": [
"to_email",
"list_id"
],
"type": "object"
},
"name": "tascan_send_task_email",
"outputSchema": null
},
{
"description": "Identify exactly which TaScan server and schema this MCP session is talking to. Call this FIRST when diagnosing anything — it makes \"dev server masquerading as production\" and \"is my fix deployed yet\" one tool call instead of an inference.",
"inputSchema": {
"properties": {},
"required": [],
"type": "object"
},
"name": "tascan_server_info",
"outputSchema": null
},
{
"description": "Update an event / task list (name, description, team_mode, multi_instance, timer_mode). team_mode and multi_instance cannot both be true.",
"inputSchema": {
"properties": {
"assigned_worker_ids": {
"description": "Worker UUIDs to assign to this event (additive — workers not named are left alone). Each gets a personal tap-to-open link. Note: a worker holds one event assignment per project — assigning moves them.",
"items": {
"type": "string"
},
"type": "array"
},
"description": {
"description": "New description",
"type": "string"
},
"list_id": {
"description": "Task list (event) ID",
"type": "string"
},
"multi_instance": {
"description": "Multi-instance — each worker gets isolated copy",
"type": "boolean"
},
"name": {
"description": "New name",
"type": "string"
},
"team_mode": {
"description": "Team mode — shared completions",
"type": "boolean"
},
"timer_mode": {
"description": "Timer mode (auto or manual)",
"type": "string"
}
},
"required": [
"list_id"
],
"type": "object"
},
"name": "tascan_update_event",
"outputSchema": null
},
{
"description": "Update an invoice: mark it paid (records paid_at), overdue, cancelled, or edit client details / notes / due date.",
"inputSchema": {
"properties": {
"client_email": {
"type": "string"
},
"client_name": {
"type": "string"
},
"client_phone": {
"type": "string"
},
"due_date": {
"type": "string"
},
"invoice_id": {
"type": "string"
},
"notes": {
"type": "string"
},
"paid_at": {
"description": "ISO timestamp (default now) when status = paid",
"type": "string"
},
"status": {
"enum": [
"draft",
"sent",
"paid",
"overdue",
"cancelled"
],
"type": "string"
}
},
"required": [
"invoice_id"
],
"type": "object"
},
"name": "tascan_update_invoice",
"outputSchema": null
},
{
"description": "Update a project (name, location, status, dates)",
"inputSchema": {
"properties": {
"end_date": {
"description": "End date (ISO)",
"type": "string"
},
"location": {
"description": "New location",
"type": "string"
},
"name": {
"description": "New name",
"type": "string"
},
"project_id": {
"description": "Project ID",
"type": "string"
},
"start_date": {
"description": "Start date (ISO)",
"type": "string"
},
"status": {
"description": "Status",
"enum": [
"active",
"archived"
],
"type": "string"
}
},
"required": [
"project_id"
],
"type": "object"
},
"name": "tascan_update_project",
"outputSchema": null
},
{
"description": "Update a subtask (title, description, response_type, response_config, requires_photo, sort_order).",
"inputSchema": {
"properties": {
"description": {
"type": "string"
},
"requires_photo": {
"type": "boolean"
},
"response_config": {
"type": "object"
},
"response_type": {
"description": "\"link\" = the worker submits a URL. \"url\" = the worker visits a preset URL and confirms. \"file\" = the worker uploads a file.",
"enum": [
"checkbox",
"number",
"text",
"choice",
"link",
"url",
"file"
],
"type": "string"
},
"sort_order": {
"type": "number"
},
"subtask_id": {
"description": "Subtask ID",
"type": "string"
},
"title": {
"type": "string"
}
},
"required": [
"subtask_id"
],
"type": "object"
},
"name": "tascan_update_subtask",
"outputSchema": null
},
{
"description": "Update a task (title, description, response_type, flags, sort_order). A task that sits in an AI agent inbox is agent input (the runner executes title + description), so ANY edit to it needs the agent:dispatch permission — agent:dispatch:code when the task is or becomes CODE:/SHELL:.",
"inputSchema": {
"properties": {
"assigned_to": {
"description": "Worker to assign this task to — pass the worker UUID (validated against your org and stored as the worker's name, which is how the worker portal matches \"my tasks\"). A plain name string is also accepted as-is. Pass null to clear.",
"type": "string"
},
"description": {
"description": "New description",
"type": "string"
},
"is_safety_checkpoint": {
"description": "Safety-critical flag",
"type": "boolean"
},
"required_equipment": {
"description": "Equipment this task depends on (free text)",
"type": "string"
},
"requires_photo": {
"description": "Require photo",
"type": "boolean"
},
"response_config": {
"description": "Response configuration. For \"choice\": {options: [...]}. See tascan_add_tasks.",
"type": "object"
},
"response_type": {
"description": "See tascan_add_tasks for guidance. \"text\" for info collection, \"photo\" for visual proof, \"checkbox\" for yes/no only, \"link\" for the worker submitting a URL, \"url\" for the worker visiting a preset URL and confirming, \"file\" for the worker uploading a file.",
"enum": [
"checkbox",
"photo",
"text",
"number",
"date",
"choice",
"link",
"url",
"file"
],
"type": "string"
},
"sort_order": {
"description": "Sort position",
"type": "number"
},
"task_id": {
"description": "Task ID",
"type": "string"
},
"title": {
"description": "New title",
"type": "string"
}
},
"required": [
"task_id"
],
"type": "object"
},
"name": "tascan_update_task",
"outputSchema": null
},
{
"description": "Update a worker profile (name, phone, email)",
"inputSchema": {
"properties": {
"email": {
"description": "New email",
"type": "string"
},
"name": {
"description": "New name",
"type": "string"
},
"phone": {
"description": "New phone",
"type": "string"
},
"worker_id": {
"description": "Worker ID",
"type": "string"
}
},
"required": [
"worker_id"
],
"type": "object"
},
"name": "tascan_update_worker",
"outputSchema": null
},
{
"description": "Update a geofenced zone — move the center, resize the radius, change the routing target, toggle zone-lock, or deactivate it (is_active=false).",
"inputSchema": {
"properties": {
"alert_on_breach": {
"type": "boolean"
},
"auto_clock_in": {
"description": "Writes a shift_start when the WORKER PAGE, while open, sees the phone enter the zone; detection is pull-based, there is no background geofencing. For a background-free presence event use a gate NFC/QR scan.",
"type": "boolean"
},
"auto_clock_out": {
"description": "Writes a shift_end when the WORKER PAGE, while open, sees the phone leave the zone; detection is pull-based, there is no background geofencing. For a background-free presence event use a gate NFC/QR scan.",
"type": "boolean"
},
"enforce_on_list": {
"type": "boolean"
},
"enter_message": {
"type": "string"
},
"is_active": {
"type": "boolean"
},
"kind": {
"enum": [
"work_site",
"hazard",
"containment",
"restricted"
],
"type": "string"
},
"lat": {
"type": "number"
},
"lng": {
"type": "number"
},
"name": {
"type": "string"
},
"notify_email": {
"type": "string"
},
"notify_on_enter": {
"type": "boolean"
},
"notify_on_exit": {
"type": "boolean"
},
"polygon": {
"description": "Replace geometry with a polygon ([[lat,lng],...], ≥3 vertices); pass null to revert to a circle",
"items": {
"items": {
"type": "number"
},
"type": "array"
},
"type": "array"
},
"ppe_photo_required": {
"type": "boolean"
},
"radius_m": {
"type": "number"
},
"required_ppe": {
"items": {
"enum": [
"hard_hat",
"safety_glasses",
"hi_vis_vest",
"gloves",
"steel_toe_boots",
"hearing_protection",
"harness",
"respirator",
"face_shield"
],
"type": "string"
},
"type": "array"
},
"sms_worker_on_enter": {
"type": "boolean"
},
"sms_worker_on_exit": {
"type": "boolean"
},
"task_list_id": {
"type": "string"
},
"task_list_on_enter": {
"type": "string"
},
"zone_id": {
"description": "Zone ID",
"type": "string"
}
},
"required": [
"zone_id"
],
"type": "object"
},
"name": "tascan_update_zone",
"outputSchema": null
},
{
"description": "Independently verify a TaScan Action Receipt JWS (protocol 6.8, POST /receipts/verify): size, envelope, signature, issuer origin, key lifecycle, hashing profile, value semantics, schema and chain check, with an online issued/serial check for the reference issuer. Public route: no TaScan scope is required by the API itself, though this MCP connection still needs some valid key to place any tools/call. Works for both the full and the public export profile. Keys come only from the issuer's own well-known key document (https://app.tascan.io/.well-known/tascan-receipt-keys.json for the reference issuer, or the equivalent well-known path for a foreign one) — this tool never supplies keys itself. Never verifies locally — always calls the reference verifier.",
"inputSchema": {
"properties": {
"jws": {
"description": "The compact JWS to verify (from tascan_get_receipt's output, or any TaScan-format receipt).",
"type": "string"
}
},
"required": [
"jws"
],
"type": "object"
},
"name": "tascan_verify_receipt",
"outputSchema": null
},
{
"description": "Hazard-zone compliance audit (OSHA / insurance): every zone crossing, PPE checkpoint verdict (complied / failed with what was missing / skipped), and breach, plus injury reports cross-referenced with the worker's last PPE checkpoint before the injury. Scope by project or zone, optionally by worker and date range. Same rows the printable Evidence Pack shows.",
"inputSchema": {
"properties": {
"project_id": {
"type": "string"
},
"since": {
"description": "ISO date/time lower bound",
"type": "string"
},
"until": {
"description": "ISO date/time upper bound",
"type": "string"
},
"worker_id": {
"type": "string"
},
"zone_id": {
"type": "string"
}
},
"required": [],
"type": "object"
},
"name": "tascan_zone_compliance",
"outputSchema": null
}
]
}Verify it yourself
curl -s https://api.teppi.xyz/v1/evidence/sha256:6b3a1db84ceecb6bd5bd236b983209bd51b5e5bd26c1784585305eb995075ce2 | sha256sum