Skip to main content

Hanary MCP Server

Hanary MCP Server for Claude Code & OpenCode - task management that keeps new work outside the priority list until the user decides.

What Hanary MCP Is For

Hanary MCP is an operating layer for AI coding assistants. It lets agents read, start, update, and complete work from Hanary while preserving the user's priority decisions.

The key rule is: agents may capture and organize new work, but they should not silently insert it into the active priority order. New tasks default to needs_decision, staying outside top-task, start, and complete candidates until the user explicitly chooses to prioritize them.

Use Hanary MCP when you want Claude Code, OpenCode, or Codex to work from your confirmed Hanary task structure instead of inventing its own task order.

Mental model:

  • Hanary owns the user's task hierarchy and priority order.
  • The AI assistant follows that order.
  • New work is captured safely as needs_decision.
  • Only explicit user intent promotes work into the active priority list.
  • executor_type: "ai" means user-approved execution delegation, not AI-owned priority judgment.
  • planning_status answers when work belongs in priority; executor_type answers who can execute it.
  • Human-owned tasks are ownership and completion boundaries, not safe advisory work boundaries: guide mode and safe non-destructive advisory help are allowed when the user asks to start, asks for guidance, or asks what to do next.
  • Meaning, priority, and completion judgment stay with the user.

API vs MCP

Hanary's REST API remains the canonical product API. Use it for first-party apps, mobile or desktop clients, custom integrations, and any workflow where you control the application code that calls Hanary.

MCP is the AI-assistant integration surface on top of that API. Use it when you want tools like Claude Code, OpenCode, or Codex to discover Hanary actions automatically through tools/list, call them through tools/call, and receive the priority-boundary guidance directly in tool schemas and server instructions.

In practice:

  • REST API is for application integrations.
  • MCP is for agent integrations.
  • hanary-mcp is the installable stdio bridge plus commands, skills, and agent guidance for local coding assistants.

MCP is not required to perform Hanary operations, but it avoids rebuilding the same tool wrapper for every AI host and keeps the assistant's behavior aligned with Hanary's user-owned priority model.

Features

  • MCP Server: Direct tool integration with Claude Code and OpenCode
  • Slash Commands: /hanary-status, /hanary-start, /hanary-done
  • Skills: Task management workflow with estimation patterns
  • Agents: Task planner that drafts complex work decomposition for user review
  • Project Sync: Safe checks, diffs, and updates for generated assistant files
  • Full Compatibility: Works with both Claude Code and OpenCode

Installation

# Using uvx (recommended)
uvx --from hanary-mcp hanary-mcp --squad my-project

# Or install globally
uv tool install hanary-mcp

Configuration

Use project-scoped setup when different repositories should bind to different Hanary squads. Run this from the project root:

uvx --from hanary-mcp hanary-mcp init --squad your-squad-slug .

This creates project-local integration files:

  • .mcp.json for Claude Code
  • opencode.json for OpenCode
  • .codex/config.toml for OpenAI Codex

Repeat the command in each project with that project's squad slug. This keeps AI assistants working inside the right Hanary squad without sharing one global --squad value across all projects.

The value after --squad is the squad slug, not the display name. For example, if Hanary shows FutureGate (futuregate), use futuregate:

uvx --from hanary-mcp hanary-mcp init --squad futuregate .

After setup, verify the local binding:

uvx --from hanary-mcp hanary-mcp doctor --squad your-squad-slug

--squad can appear before or after doctor, init, or sync. For doctor, the same applies to --api-url and --token: explicit CLI values take precedence over environment defaults. If an option is explicitly given on both sides of the command, the later value wins.

Doctor prints the requested scope and checks project files against that scope; it does not infer the requested scope from those files. It reports project configuration and remote diagnostics separately. A successful squad-list lookup is not a membership check: Requested squad access check verifies access to the named squad, or explicitly shows SKIPPED in personal mode. The tool contract check compares the advertised tool catalog; it does not execute every tool or verify the MCP process already running in your assistant.

An actual project scope mismatch still exits with status 1, even when remote diagnostics succeed. Review the listed configuration arguments or rerun doctor with the intended scope; doctor never rewrites project files. Missing project files and a client without tools/list diagnostic support are reported as skipped, not failed; a skipped catalog leaves the remote summary INCOMPLETE rather than OK. A catalog request that fails still causes a failed result.

Inside an AI assistant, use get_current_scope when the active project or squad is unclear before creating, starting, completing, or reordering tasks. In project-scoped squad mode, the MCP server exposes the squad as the working boundary: use get_top_task for "what should I do next" inside that project. get_overall_top_task is intentionally not exposed in squad mode; use a separate personal/global Hanary MCP only when the user explicitly asks to leave the project scope.

Keeping Project Files Synced

Use hanary-mcp sync after upgrading hanary-mcp when an existing project should receive updated commands, skills, agents, or generated MCP config.

Start with a status check:

uvx --from hanary-mcp hanary-mcp sync --squad your-squad-slug .

Review diffs before writing:

uvx --from hanary-mcp hanary-mcp sync --squad your-squad-slug --dry-run .

Write only safe changes:

uvx --from hanary-mcp hanary-mcp sync --squad your-squad-slug --write .

sync --write creates missing files and updates files that still match the last managed template hash. It does not overwrite user-modified files. Local config files such as .mcp.json, opencode.json, and .codex/config.toml are marked for review instead of being overwritten, because they may contain squad slugs, tokens, uv cache settings, or other project-specific choices.

Use init --force only when you intentionally want to overwrite existing generated files. It can replace local edits in .codex/config.toml, .mcp.json, and opencode.json; after using it, re-check any OS-specific command, token, and cache settings.

The sync manifest is stored in .hanary-mcp-sync.json. It records template hashes for files managed by hanary-mcp, so future upgrades can distinguish safe generated-file updates from user edits. AI guidance changes are listed separately in sync output because they affect assistant judgment boundaries.

Claude Code Setup

  1. Set your API token as a system environment variable:
export HANARY_API_TOKEN='your-token-here'

On Windows PowerShell, set a persistent user environment variable:

[Environment]::SetEnvironmentVariable("HANARY_API_TOKEN", "your-token-here", "User")

Or set it only for the current PowerShell session:

$env:HANARY_API_TOKEN = "your-token-here"

Restart your AI coding assistant after changing environment variables. Existing Codex, Claude Code, or OpenCode processes do not inherit newly saved user environment variables; if they start the MCP server without the token, you may see an initialize/handshake failure such as connection closed.

  1. Prefer hanary-mcp init above, or add this to your project's .mcp.json manually:
{
  "mcpServers": {
    "hanary": {
      "command": "uvx",
      "args": ["--refresh-package", "hanary-mcp", "--from", "hanary-mcp", "hanary-mcp", "--squad", "your-squad-slug"]
    }
  }
}

Global CLI registration is useful only when one Hanary squad should be used everywhere:

claude mcp add hanary -- uvx --refresh-package hanary-mcp --from hanary-mcp hanary-mcp --squad your-squad-slug

Do not use global CLI registration with --squad when you need project-by-project squad separation. In that case, keep the --squad binding in each project's .mcp.json or .codex/config.toml instead.

OpenAI Codex Notes

hanary-mcp init generates .codex/config.toml for the current operating system. On macOS/Linux it uses zsh -lc so shell profile environment variables can load. On native Windows it runs uvx directly because zsh is not available by default:

[mcp_servers.hanary]
command = "uvx"
args = ["--refresh-package", "hanary-mcp", "--from", "hanary-mcp", "hanary-mcp", "--squad", "your-squad-slug"]

[mcp_servers.hanary.env]
UV_CACHE_DIR = ".uv-cache"

Keep UV_CACHE_DIR in the project root, such as .uv-cache, so Codex sandboxed runs can write to it. If you edit the Codex config manually on Windows, avoid copying a macOS/Linux zsh -lc command into that file.

Environment Variables

Set these in your shell profile (.bashrc, .zshrc, etc.) or OS user environment:

Variable Required Description
HANARY_API_TOKEN Yes Your Hanary API token
HANARY_API_URL No API URL (default: https://hanary.org)

Recovering a task write after a lost response

create_task and update_task accept an optional idempotency_key. Generate and retain a nonsecret unique key before sending one intended write. If its response is lost, call get_mutation_result(idempotency_key="the-original-key") in the same scope, or resend the original tool with exactly the same key and arguments. The bridge performs no automatic write retries.

An applied receipt confirms the write committed. A replay returns the same task ID and its current state, preserving later edits. not_recorded does not prove failure: the request might still be running. Different arguments with a used key are rejected. Never generate a new key merely to retry. Deleted, moved, or inaccessible tasks are not recreated or exposed by recovery.

The backend must advertise this contract before the bridge sends a keyed write. If no key was supplied, inspect the task and records after an uncertain response; legacy writes cannot be automatically retried safely. Receipt keys do not provide conflict detection for separate intentional edits with different keys.

Available Tools

Default Agent Workflow

Use Hanary MCP around one confirmed focus at a time:

get_top_task -> get_task/update_task for context and notes -> start_task
-> do the work -> stop_task/complete_task against the saved user-defined criterion
-> get_top_task for the next focus

list_tasks, search_tasks, list_completed_tasks, list_work_activity, get_tasks_summary, and get_task_tree are context tools. They help inspect related work, historical completion or activity, duplicates, blockers, hierarchy, or review state, but they should not replace get_top_task as the source of current focus. Use list_completed_tasks for completed_at recall and list_work_activity with basis="activity" for work performed in an actual date range. In get_tasks_summary, status_counts uses explicit status meanings: started/in-progress task context means started_at is set and completed_at is nil. highest_priority_started_task is the first started task in summary priority order, not the current AI focus. This is separate from active time tracking; use get_task with include_time_summary=true to inspect has_active_session and active_session_started_at. When this server is started with --squad, get_top_task is the project focus boundary. Do not switch to overall/global focus unless the user explicitly asks to work outside the current project squad.

If get_top_task returns is_llm_boundary=true, treat it as an execution boundary, not as permission to pick from a list and not as an advisory stop signal. The response may include human_prioritized_candidates: these are user-prioritized tasks that are still marked executor_type: "human". Report that prioritized work exists but has not been delegated to AI for execution. Do not change executor_type, start execution work, or skip to a lower-priority AI task unless the user explicitly delegates AI execution or explicitly chooses that lower-priority work. If advisory_allowed=true and the user asks to start, asks for help, asks what to do next, or asks to work together, default to guide mode instead of only asking for AI delegation and stopping. Starting advisory time tracking for the current top-priority human-owned task is allowed in that flow; it is a collaboration record, not AI execution delegation.

That boundary does not block safe advisory support. Human-owned tasks create an ownership and completion boundary, not a safe advisory work boundary. If advisory_allowed=true and the user asks to start, asks for help with the human-owned task, asks what to do next, or says completion/final approval remains theirs, the assistant should continue in guide mode without asking for extra permission for non-destructive support work. Guide mode begins by briefly stating that the task remains human-owned, then reading the task context and providing the first 1-3 concrete user actions.

Safe autonomous advisory work includes reading Hanary task details, completion criteria, notes, and approach; reading related local documents; running read-only inspection commands such as rg, ls, sed, and git status; public research; summarizing findings; first-step guidance; checklists; verification plans; evidence organization; draft communication; interpretations of user-provided results; and creating new non-overwriting support artifacts such as Markdown reports under docs/, guides/, reports/, or notes/. When creating such an artifact, record its path and a short summary in Hanary notes and leave completion approval to the user.

Advisory time tracking is allowed for the current top-priority human-owned task when advisory_allowed=true and the user asks to start, asks for help, asks what to do next, or asks to work together. start_task in this case records advisory work as a collaboration record; it does not change executor_type, grant completion authority, or grant priority authority. Maintain an already active session; do not stop user-started sessions without confirmation, and do not stop any advisory session unless the user asks to stop, wrap up, or says the work is here for now.

External Reply or Approval Wait

When the current top task is waiting only on an external reply or approval, do not leave it occupying focus indefinitely and do not hold it automatically. Inspect its completion criteria, notes, approach, and children; confirm that the external request has been sent, no independently executable work remains, and time tracking is inactive. Never stop an active session automatically for this transition. Then call assess_task_hold to get a non-mutating hold_recommended result with the waiting reason, waiting time, resume condition, and next_actionable_task. Ask before calling hold_task unless the user already gave explicit intent such as "hold this until the reply arrives." hold_task requires a reason plus a resume condition or follow-up time. It preserves rank, planning_status, dependencies, and time sessions while storing a durable operational hold period; it never creates a judgment record automatically. Use get_task_hold_history to recover prior context. Call unhold_task only after explicit user intent; it may add a short resume note and returns the task to its existing priority.

Prerequisites vs Hold

add_dependency represents a prerequisite relationship. Its legacy fields map blocking_task_id to the prerequisite and blocked_task_id to the dependent task. dependency_type defaults to blocks_start, which excludes the dependent task and its descendants from top-task selection and prevents starting or completion. Use blocks_completion when work and time tracking may proceed but review submission and completion must wait; that gate does not propagate to descendants. Use update_dependency_type to change the gate without deleting the relationship. Every gate is derived: rank and planning_status do not change, and completing the prerequisite clears the applicable gate automatically.

Use a dependency when a real Hanary task must finish first. Use hold_task when progress depends on an external reply or condition that has no Hanary task. Do not apply both mechanisms for the same waiting reason.

The assistant must ask first before modifying, deleting, or overwriting existing files; changing source code, circuit designs, or config; completing tasks; stopping user-started time sessions; stopping any time session without a user stop/wrap-up request; changing executor_type; changing priority; committing, pushing, or deploying; sending external messages; placing orders, payments, or bookings; or define completion criteria for the user; or making/replacing the user's final judgment or completion approval.

Personal and Squad Mutation Boundary

Personal/global MCP keeps the normal tools for the user's personal tasks. An accessible squad task does not become personally governed work: membership and visibility provide context, not mutation authority. Only the directly assigned, accepted assignee may start, complete, hold, or unhold that squad task, append execution evidence through approach, notes, or retrospective, create an AI judgment draft, record their own historical work, and stop or clean up their own time session.

Squad priority, planning status, hierarchy, shared fields, dependencies, links, deletion, completion reversal, relocation, and planning-session mutations require the matching project-bound --squad context and server authorization. Tools such as reorder_task remain available in personal mode for personal work; their presence is not permission to apply them to a visible squad task.

Resuming saved work

Call get_task(task_id="123", include_resume_context=true) to add a read-only resume_context containing saved purpose, completion criteria, notes, holds, prerequisites, current judgments, an accepted next action when recorded, and AI report freshness. Source IDs and timestamps accompany saved records; full note text is preserved. Omit the option or use false to keep the existing response. The option accepts only a boolean.

not_recorded means no applicable saved record was found; unavailable means it could not be confirmed. A stale AI report means unknown liveness, not proof that an external process stopped. Multiple accepted next actions remain visible as conflicting candidates. Reading never generates or accepts a next action, changes priorities or holds, or starts timers or execution. Use get_top_task for the current priority and the existing history tools for older records.

Task Management

  • get_current_scope - Show whether this MCP server is in personal mode or bound to a project squad
  • get_top_task - Primary tool for ordinary top-priority and "what should I do next?" questions; returns the current AI focus without bypassing the user's confirmed priority order
  • get_overall_top_task - Personal mode only and only for an explicit all-squad request. Returns personal_top, squad_tops, and selection metadata; it does not invent a cross-scope winner when no global order is confirmed. This tool is not exposed when the MCP server is bound to a project squad.
  • get_task - Inspect a specific task with its purpose, attempts & decisions, references & results, children, ancestors, and time summary
  • list_judgment_records - Read the append-only problem → assessment → proposal → decision → outcome history attached to one task
  • create_judgment_record - Record a concise AI-authored problem/assessment/proposal draft. It never records user acceptance or rejection.
  • withdraw_judgment_proposal - After explicit user confirmation of the exact task_id, proposal_event_id, and reason, withdraw a pending AI proposal from review. Its effective status becomes withdrawn, not rejected. Original content, actor, time, and reason remain in history; nothing is permanently deleted.
  • supersede_judgment_proposal - With explicit user confirmation, provide the same fields plus replacement_proposal_id to retain an already-existing pending AI proposal in the same task and dimension. The old proposal becomes superseded; no third proposal is created and the target's content and acceptance state are unchanged. Human-authored or closed proposals cannot be cleaned up via MCP. Report cleanup_applied, affected IDs and effective statuses, and the remaining decision_targets with exact links. Neither cleanup action is acceptance or authorization to change or execute a task. Re-list history after an uncertain response before retrying. Original events keep their historical status; follow replacement_proposal_id on cleanup events to see the connection.
  • replace_judgment_proposal - Replace a pending AI proposal using its exact task_id and proposal_event_id. Optional problem_raised, assessment, and proposal inherit omitted sections; at least one must change. The old thread becomes superseded and a full, unaccepted AI snapshot becomes the new review target. Human-authored, accepted, rejected, and already superseded proposals cannot be replaced through MCP. Independent alternative proposals are preserved. Text saying “replaces X” does not perform replacement. After a timeout or stale-target error, re-list history before retrying; never create another proposal as a fallback. Check replacement_applied, show previous_proposal and replacement_proposal IDs, and present the returned decision_target with its exact review link. This does not change task fields, priority, or execution authorization; final acceptance/rejection stays web-only.
  • list_tasks - List tasks as supporting context; use get_tasks_summary for overviews
  • search_tasks - Find related tasks, duplicates, or blockers without choosing focus automatically
  • list_completed_tasks - List completed tasks by completed_at date range for historical recall and retrospectives
  • list_work_activity - List the authenticated user's actual activity by performed date with timer/manual provenance and exact/estimated accuracy
  • get_task_tree - Inspect hierarchy and decomposition without treating the tree as a new priority order
  • create_task - Create a new task. In personal mode, pass a squad_slug selected from list_my_squads to capture root squad work as a needs_decision proposal; omit parent_id and rank, and omit the slug for personal work. Adding a squad child or prioritized squad insertion requires the matching project-bound --squad context.
  • update_task - Update task title, description, completion-criteria selection, executor, purpose/background/approach/notes/retrospective, or due date. Set due_date with YYYY-MM-DD, send explicit null to clear it, or omit the field to keep the current value unchanged.
  • complete_task - Mark task as completed against the user's saved completion-criteria selection
  • uncomplete_task - Mark task as incomplete
  • delete_task - Soft delete a task
  • reorder_task / batch_reorder_tasks - Change priority order only after explicit user-confirmed placement
  • prioritize_task / batch_prioritize_tasks - Atomically promote existing tasks into the priority chain using an explicit user-confirmed order
  • move_task / batch_move_tasks - Clarify hierarchy inside the current personal or squad scope after user confirmation. They never expose personal work to a squad; use relocate_task_to_squad from the matching project-bound squad context for that visibility change.
  • list_reference_child_violations - Read-only audit for legacy personal task roots hidden under squad-reference pointers or actual squad tasks without inherited squad scope. It never moves or shares tasks.
  • relocate_task_to_squad - Project-bound squad mode only. After explicit user choice, move one repairable personal task subtree into the bound squad and pass a confirmation summarizing that choice. Personal/global mode reports the target squad but does not expose this mutation.
  • assess_task_hold - Evaluate an external-wait hold candidate without changing task state or time tracking
  • hold_task / unhold_task - Open or close a durable hold period at the existing priority only after explicit user intent
  • get_task_hold_history - Read newest hold periods without changing task state
  • record_historical_completion - Record an explicitly confirmed past completion instant separately from the time it was entered; requires an existing saved completion standard
  • add_dependency - Add a typed prerequisite that defaults to blocks_start
  • update_dependency_type - Change an existing prerequisite between blocks_start and blocks_completion without changing task priority or planning status
  • remove_dependency - Remove an existing prerequisite relationship

Historical Work Records

Do not start and stop today's timer to represent work performed on an earlier date. First call assess_historical_work with the intended payload and present the normalized performed date, duration, and any conflict. Call record_historical_work only after the user confirms that assessment.

Use entry_mode="exact_interval" only when both real timestamps are known. If the user remembers only the local date and duration, use entry_mode="duration_only" with performed_on and duration_minutes. Mark an approximate memory with accuracy="estimated" instead of inventing precise timestamps. Reuse an idempotency_key only for an identical retry.

Historical activity and task completion are separate records. record_historical_work never completes a task; use record_historical_completion only after the user explicitly confirms the actual completion instant and the task already has a saved user-confirmed completion standard. Use list_work_activity for performed-date recall and list_completed_tasks for completion-date recall.

Squad

  • list_my_squads - List squad display names and unique slugs. In personal mode, use it to resolve a user-named squad before passing its returned slug to create_task.
  • get_squad - Get squad details and shared-problem context
  • list_squad_members - List members who share the squad problem context
  • list_squad_events - List events and deadlines for shared-problem coordination
  • get_online_members - Check current presence when coordination is needed
  • start_planning_session / stop_planning_session - Change squad planning-session state only from the matching project-bound --squad context

Messages

  • list_messages - List squad messages for recent decisions, blockers, and shared context
  • create_message - Send a squad message around the shared problem, decisions, or blockers

Task Creation Policy

create_task records new work without assuming it belongs in the priority list. By default, new tasks are created as needs_decision, so they stay outside top-task, start, or complete candidates until the user decides whether to break them down or place them into priority. Use planning_status: "prioritized" only when the user explicitly wants the task placed in the priority order now. rank is ignored unless planning_status: "prioritized" is explicit, and is required for prioritized creation except for the first executable child under a prioritized parent with no prioritized siblings. Use get_task on the parent first when unsure; its child_creation_policy reports the parent planning_status, direct incomplete child counts by planning status, prioritized child count, and whether rankless first executable child creation is allowed.

When a user in personal mode asks to add work to a named squad, call list_my_squads before creating. Prefer an exact returned slug; otherwise require one unique exact display-name match. If there is no exact match or multiple squads share the display name, ask the user to choose from the returned names and slugs instead of guessing. Call create_task with that returned squad_slug, omit parent_id and rank, and omit planning_status or use needs_decision. This captures a root proposal without changing the squad's shared hierarchy or agreed priority. In project-bound mode, task creation always stays in the configured --squad, a per-call squad_slug override is rejected, and adding a child or explicitly confirmed prioritized insertion is available.

A task with squad_ref_id is a personal dashboard reference to a squad, not an actual squad task parent. Never use that reference as parent_id. From personal/global mode, create only a squad root proposal with squad_slug and no parent. In the matching project-bound squad context, a child may use an actual squad task whose squad_id identifies that same squad.

Use list_reference_child_violations to detect legacy personal children that already exist under squad references or actual squad tasks without inherited squad scope. The audit is read-only: it returns each entry's violation_type, repairable flag, blocking_reasons, descendant_count, and target squad without moving or sharing anything. In personal/global mode, present the findings and tell the user which target --squad context to enter; the wrapper intentionally returns no executable relocation action. In that matching project-bound context, require an explicit user choice before calling relocate_task_to_squad, because relocation exposes the entire task subtree to squad members. Relocate only entries marked repairable, pass a non-empty confirmation, and do not pass a per-call squad override.

References & Results and child tasks have different jobs. record_update is only an update_task input. create_task accepts initial purpose/background/approach/notes without this object. Include record_update with every update_task record write; use it for all References & Results and Attempts & Decisions writes while keeping purpose/background/retrospective in their named update_task fields. Put links, research notes, command output, formulas, and deliverables in references_results (stored as notes), and put what was tried, blockers, and reasons for an already chosen direction change in attempts_decisions (stored as approach). Always include the required action_items array, even for evidence-only updates, and put uncertain placement in optional ambiguous_items. In update_task, do not send legacy top-level notes or approach; they remain compatibility-only during rollout. If action_items or ambiguous_items is non-empty, Hanary changes nothing and returns needs_decision child task candidates for user review. This is an explicit caller classification rather than an AI classifier, and Hanary never creates or prioritizes those candidates automatically. If a checklist item can be executed independently, have its result recorded separately, and be judged complete on its own, create it as a child task candidate with parent_id instead of burying it in a record. Measurements, tests, checks, and concrete actions often belong in child task candidates when they can be performed one by one. Creating child task candidates clarifies hierarchy only; it does not make them executable or prioritized unless the user explicitly asks for priority placement.

When a problem, assessment, or improvement proposal materially changes a task's purpose, approach, scope, completion criteria, priority, next action, or shared commitment, use create_judgment_record instead of flattening the turning point into a mutable note. Summarize the transition and keep only an opaque source reference; never copy raw conversations, prompts, credentials, or secrets. AI-created records remain proposals. list_judgment_records preserves adopted, rejected, and superseded history, but MCP intentionally exposes no decision tool: silence, an AI recommendation, and general execution delegation are not acceptance, and final acceptance or rejection must come from an authenticated user action in Hanary's web UI.

After create_judgment_record, assistants should inspect user_decision_required and decision_target. When a decision is required, the same user-facing response should name the returned task ID and title, dimension, exact proposal summary, judgment thread ID, proposal event ID, and provide the returned decision_url as a direct link. Assistants must never invent or reconstruct a missing URL. If no URL is returned, they should say so and provide the remaining target details. A false user_decision_required with decision_target: null requires no decision request; a required decision with no target should be reported as an inconsistent response rather than guessed. The actual decision remains web-only.

If the user explicitly asks to make a new child task executable now and there are no prioritized siblings under its prioritized parent, create it in one call with parent_id and planning_status: "prioritized"; Hanary places that first executable child at rank: 0 without a comparison. needs_decision and priority_pending siblings do not block this first executable child exception because they are not priority comparison targets. If prioritized siblings already exist, ask the user for sibling order and include a rank from the user's confirmed order. Otherwise, even the first child task under a parent remains a needs_decision candidate.

For existing tasks, plain reordering does not finalize execution readiness. After the user explicitly confirms or delegates priority, use prioritize_task for one existing task or batch_prioritize_tasks for a complete sibling order. For root-level work, explicitly pass expected_parent_id: null or parent_id: null; do not omit the field. A non-null parent must be the prioritized parent the user reviewed. These tools atomically update planning_status and sibling ranks. The batch tool rejects omitted existing prioritized siblings by default; use append_after only when the user explicitly keeps them after the listed tasks.

planning_status and executor_type are separate axes. planning_status answers when the task belongs in the priority chain; executor_type answers who can execute it. A clear coding task can be planning_status: "prioritized" and executor_type: "ai" when the user has placed it into priority and the cause, likely fix location, and verifiable completion criteria are known. A human task can also be prioritized when it requires hardware assembly, measurement, purchase, installation, field operation, external approval, or final human judgment.

When executor_type is omitted, Hanary assigns the safe human default without automatic executor classification or recommendation. Send executor_type: "ai" only after the user explicitly approves AI execution. Mixed work should usually be split: create the explicitly delegated AI implementation task separately from the human real-device or field validation task.

Priority placement and AI delegation are separate decisions. A task can be planning_status: "prioritized" and still remain a human task. In that case get_top_task should stop execution actions at the boundary and explain that the user must explicitly delegate AI execution or explicitly choose lower-priority AI work before the assistant changes executor_type, starts execution work, or moves down the priority list. If advisory_allowed=true, the assistant should default to guide mode when the user asks to start, asks for help, or asks what to do next.

For human tasks, guidance is still useful and allowed. The assistant can help the person perform the task through safe autonomous advisory work: read-only inspection, public research, summaries, checklists, verification plans, safety/risk notes, evidence organization, draft communication, draft measurement criteria for user confirmation, new non-overwriting support documents, and interpretations of results the user reports back. This is advisory support, not task execution or final judgment. The assistant should give the first 1-3 concrete user steps rather than stopping at an AI delegation prompt.

For the current top-priority human task, advisory time tracking is also allowed as a collaboration record when the user asks to start, asks for help, asks what to do next, or asks to work together. This use of start_task does not delegate completion, change executor type, or change priority. Stopping time tracking is intentionally stricter: do not stop a user-started session without confirmation, and do not stop any advisory session unless the user asks to stop, wrap up, or says the work is here for now.

When starting a child task while an ancestor task has an active session, start_task defaults to ancestor_session_action: "ask" and returns a confirmation payload instead of silently stopping the ancestor session. After the user confirms, call start_task with ancestor_session_action: "switch" or use switch_active_session(from_task_id, to_task_id) to stop the ancestor session and start the child session.

Completion Policy

complete_task should be called against the user's saved completion-criteria selection. A saved completion_criteria_source: "title" means the user explicitly confirmed that the task title itself is the completion standard; do not repeat the title in completion_criteria. A saved completion_criteria_source: "explicit" means the task has a separate completion_criteria. Reuse either saved selection by calling complete_task with only task_id (and optional retrospective); do not prompt for or resend a criterion that is already saved.

Only when no completion-criteria source is saved should the assistant ask the user to choose. If the user explicitly confirms that the title is sufficient, call complete_task with completion_criteria_source: "title". If the user defines a separate standard, send completion_criteria_source: "explicit" together with completion_criteria. Never infer that a title is sufficient, copy it into the separate field, or invent a criterion. If the effective criteria are clear and verifiable, the agent may judge completion from evidence such as tests, deployment status, or document changes; if sufficiency is vague or depends on taste, values, social agreement, or priority judgment, ask the user to confirm it.

AI execution and human time

Autonomous AI work uses a separate execution record, not the user's timer:

  1. Read get_top_task; only this scope's current hierarchical top task with explicit executor_type: "ai" delegation can start.
  2. Call start_delegated_execution with task_id, a stable external_session_id, and an idempotency_key. Retain the IDs and returned version; reuse the same key on retries. If the host has no conversation ID, generate and retain an opaque ID. The bridge's process run ID is not a conversation identifier.
  3. Report running, waiting, or blocked with update_execution_status, supplying the execution ID, external session ID, and expected_version.
  4. Call finish_delegated_execution with succeeded or failed. This does not complete or approve the task; existing completion criteria and user approval still apply to complete_task separately.

Use list_delegated_executions(task_id) for the active run and recent history. get_task and get_top_task include execution_context. Different scopes can run concurrently alongside a human timer. One task cannot have two active AI claims. AI wall-clock duration includes waits; it is not human time or compute usage and is not added to existing human time statistics.

A heartbeat missing for 15 minutes means liveness is unknown, not stopped. Hanary does not automatically release stale claims or cancel external processes. After confirming the host is stopped, the owner can use cancel_delegated_execution with the execution ID, version, and reason, even if the old conversation identity was lost. Priority changes do not cancel runs.

start_task remains for human work and intentional advisory collaboration. Replacing any other active human timer requires user confirmation and the exact expected_active_session_id from the prompt; a stale source is rejected. Do not stop another timer as a workaround. If the execution tools are unavailable, update/reconnect the integration instead of substituting start_task for AI work.

Development

# Clone and install
git clone https://github.com/hanary/hanary-mcp.git
cd hanary-mcp
uv sync

# Run locally
HANARY_API_TOKEN=your_token uv run hanary-mcp --squad test

# Run tests
uv run --with pytest python -m pytest

Enhanced Features

Beyond the MCP tools, this project includes commands, skills, and agents for better UX.

Slash Commands

Command Description
/hanary-status Show current task status and squad overview
/hanary-start Begin working on top priority task
/hanary-done Complete current task against user-defined completion criteria and get next

Skills

  • hanary-workflow: Complete task management workflow with estimation patterns and best practices

Agents

  • task-planner: Drafts structured subtasks and estimates for user review

Platform Setup

Claude Code

Files auto-discovered from .claude/ directory:

.claude/
├── commands/          # /hanary-status, /hanary-start, /hanary-done
├── skills/
│   └── hanary-workflow/
│       └── SKILL.md
└── agents/
    └── task-planner.md

For project-specific squad separation, use the .mcp.json generated by hanary-mcp init --squad ... in each project. Global CLI registration binds hanary to one squad across projects, so use it only for a single shared default:

claude mcp add hanary -- uvx --refresh-package hanary-mcp --from hanary-mcp hanary-mcp

OpenCode

Files auto-discovered from .opencode/ directory:

.opencode/
├── commands/          # /hanary-status, /hanary-start, /hanary-done
└── agents/
    └── task-planner.md

Skills are shared via .claude/skills/ (OpenCode reads both .opencode/skills/ and .claude/skills/).

Configuration in opencode.json:

{
  "$schema": "https://opencode.ai/config.json",
  "mcpServers": {
    "hanary": {
      "command": "uvx",
      "args": ["--refresh-package", "hanary-mcp", "--from", "hanary-mcp", "hanary-mcp"]
    }
  }
}

Note: HANARY_API_TOKEN must be set as a system environment variable.

Directory Structure

hanary-mcp/
├── .claude/                    # Claude Code files
│   ├── commands/
│   │   ├── hanary-status.md
│   │   ├── hanary-start.md
│   │   └── hanary-done.md
│   ├── skills/
│   │   └── hanary-workflow/
│   │       ├── SKILL.md
│   │       └── references/
│   └── agents/
│       └── task-planner.md
├── .opencode/                  # OpenCode files
│   ├── commands/
│   │   ├── hanary-status.md
│   │   ├── hanary-start.md
│   │   └── hanary-done.md
│   └── agents/
│       └── task-planner.md
├── .mcp.json                   # MCP server config
├── opencode.json               # OpenCode config
└── src/hanary_mcp/             # MCP Server implementation

License

MIT

Decision context in read responses

  • detect_overload checks configured risk signals, not available capacity. Its assessment reports scope and per-rule candidate, evaluated, missing-data and matched counts. No signal does not mean the schedule has spare time. In a squad-bound connection the calculation is restricted to the user's work in that squad; personal/global mode retains the accessible user-work scope.
  • list_work_activity.review_summary reports total, pending-review and excluding-pending-review minutes for the returned page's activity slices. get_task with include_time_summary provides the same breakdown under time_summary.review_summary for the task across all actors and all time, including corrections and active sessions. Pending session IDs allow review; approval and correction remain subject to session ownership. exact describes recorded interval boundaries, and excluding pending review does not establish that the user verified every remaining record.
  • Use lifecycle_status for the task's own state. Child progress and active time tracking are separate. Legacy status meanings are documented in task_state_semantics, including compact task summaries.
  • list_hold_reviews accepts due, needs_context, undated, or all. needs_context finds missing reasons or return paths, not every undated wait. update_hold_review supplements the current reason/condition or reschedules follow_up_at; omit a field to keep it, use null to clear an optional field. It preserves original hold history, hold state, priority and timers. Resume explicitly with unhold_task when the user chooses to do so.

Connection capabilities can differ. doctor checks the advertised tool inventory, executor default and structured update input against the bridge's contract; a missing field is a connection mismatch, not an instruction to invent an input.

Criteria and verification reports

Use get_task(include_resume_context=true) to read saved criteria and reported evidence together. record_verification_report appends a report against the exact expected_criteria_source and expected_criteria_text you read, with a retained idempotency_key, checked scope, optional limitations, and up to ten items (criterion, outcome: met/unmet/unknown, optional checks, evidence, and HTTP(S) result_url). A changed criterion rejects a stale submission.

list_verification_reports reads three reports per page; pass its next_before_id as before_id for older reports. The web task resume panel shows the same records and highlights changes to the original criterion. Corrections are new reports; existing notes remain intact. After a lost write response, use get_mutation_result or retry the identical request with its original key. Reports are AI-reported evidence, not independently verified tests, complete criterion coverage, user approval, or automatic task completion.

First-action drafts

Use get_task(task_id="…", include_planning_context=true) to reuse the saved goal, current purpose and completion picture. The optional planning_context contains original note IDs, explicit missing states and drafting guidance. Present 1–3 small first-action candidates with reasons, asking only for missing information that changes the first action. Let the user edit, select or cancel before saving accepted candidates through create_task. Its default needs_decision state keeps priority confirmation separate; reading context or drafting candidates does not assign an executor, choose completion criteria, or start a timer or execution. Existing executor inheritance still applies when a user accepts a child task. Omitting the option preserves the existing response.

Release files for hanary-mcp 0.32.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hanary-mcp 0.32.0
File Size Uploaded
hanary_mcp-0.32.0.tar.gz 222.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for hanary-mcp 0.32.0
File Interpreter ABI Platform
hanary_mcp-0.32.0-py3-none-any.whl Python 3 none any Details

Total release size: 334.1 kB

Release files / hanary_mcp-0.32.0.tar.gz

Download URL hanary_mcp-0.32.0.tar.gz
Size 222.7 kB
Tags Source
SHA-256 checksum
How to use checksums
a8be56ee81be9d4b451ba395f2b1cd54fa7295e990cc357496c21c29b59bce2f
BLAKE2b-256 checksum
How to use checksums
f502d136c663b9289c99cabda45851d60cc8ee4ecef61b74e8ae7503d0285772
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release files / hanary_mcp-0.32.0-py3-none-any.whl

Download URL hanary_mcp-0.32.0-py3-none-any.whl
Size 111.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a8e6a323048f82fd6e329ffc755caff3c6dff0b6f7fd161d0c77ae593bc51917
BLAKE2b-256 checksum
How to use checksums
7c38df6425f04723387613ff386efa9ca08601ea29e6ccf655b783a04b603212
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release history Release notifications | RSS feed

0.33.0

2 release files

This release

0.32.0 This release

2 release files

0.31.0

2 release files

0.30.0

2 release files

0.29.0

2 release files

0.28.0

2 release files

0.27.1

2 release files

0.27.0

2 release files

0.26.0

2 release files

0.25.0

2 release files

0.22.9

2 release files

0.22.8

2 release files

0.22.7

2 release files

0.22.6

2 release files

0.22.5

2 release files

0.22.4

2 release files

0.22.3

2 release files

0.22.2

2 release files

0.22.1

2 release files

0.22.0

2 release files

0.21.0

2 release files

0.20.0

2 release files

0.19.0

2 release files

0.18.0

2 release files

0.13.0

2 release files

0.12.3

2 release files

0.12.2

2 release files

0.12.1

2 release files

0.12.0

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.7

2 release files

0.9.6

2 release files

0.9.5

2 release files

0.9.4

2 release files

0.9.3

2 release files

0.9.2

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page