Skip to content
claudemods

Human in the loop Claude Code mod: keep the tasks only you can do in front of you

Claude assigns you the tasks only you can do. They wait in a My tasks pane, counted under the prompt, until you answer.

Permissions

  • Intercepts tool callsSees every tool call Claude makes (tool.call / tool.check) and could block or change it.
  • Reads your promptsCan see what you type and the conversation transcript (prompt.* / session.append / session.messages).
  • Changes the UIDraws into the Claude Code interface: bands, panes, status text, toasts (ui.render / $.ui.*).
  • Adds commands/toolsRegisters new slash commands or tools that you or Claude can invoke ($.command.register / $.tool.register).
  • Stores dataKeeps data between sessions in the plugin's private store ($.store.*).
tested with
v2.1.310
last tested
requires
Claude Code ≥ 2.1.287
surfaces
pane, status, toast, transcript

Install inside Claude Code:

/plugin install human-in-the-loop --marketplace tzafrir/human-in-the-loop
All install options ↓

What does this mod do?

Human in the loop is a community mod by Tzafrir Rehan (tzafrir). It is a human in the loop Claude Code mod for one situation: Claude needs something only you can do, such as a key put in .env, an approval on staging, a command on your own machine or a decision. Normally it says so in the middle of a reply, and the ask scrolls away. With this mod Claude assigns the ask as a task instead.

The mod registers three tools, assign_task, list_tasks and withdraw_task, and adds a few lines to the system prompt that tell Claude to use assign_task for anything only you can do, reviews of its work included. A task has a title, a one-sentence reason, an optional "done when", and a kind: do (you do it and mark it done), answer (Claude needs your words) or choose (pick one of 2 to 4 options). Open tasks wait in a My tasks pane and are counted in the status line under the prompt, like ☐ 1 task for you · /my-tasks. You can reply with Done, an option, an answer or a rejection with a reason.

Tasks do not block Claude. It carries on with other work, and your response reaches it as a message when you give it. Limits from the code: at most 5 open tasks, the same ask twice is one task, and only the main agent can assign them.

Demo

The recording starts Claude Code with the mod loaded in the small demo project and asks Claude to use assign_task to give us one task: put STRIPE_KEY in .env. Claude calls the tool, and the transcript shows a yellow ☐ Assigned you a task: Put your STRIPE_KEY in the .env file row, followed by the tool result saying the task is #1 and that open tasks are 1 of 5. Under the prompt the status line reads ☐ 1 task for you · /my-tasks, and a toast at the right of the footer says human-in-the-loop: Claude assigned you a task: Put your STRIPE_KEY in the .env file. See /my-tasks. In this narrow recording the pane did not seat itself, which is what the toast is for, so the clip does not show the pane or answering a task.

Install

Use any of the methods in the install block; they install straight from the author's own marketplace. Start a new session, or run /reload-plugins, after installing. /my-tasks opens the pane.

$ install human-in-the-loop

Requires Claude Code ≥ 2.1.287

Installs from the author's own marketplace: tzafrir/human-in-the-loop

  1. 1.One line, inside Claude Code

    /plugin install human-in-the-loop --marketplace tzafrir/human-in-the-loop

    Paste into a running session (v2.1.275+). Claude Code asks to add the marketplace first.

  2. 2.From your shell

    claude plugin marketplace add tzafrir/human-in-the-loop
    claude plugin install human-in-the-loop@human-in-the-loop

    Then run /reload-plugins in any session that is already open.

  3. 3.Try it without installing

    git clone https://github.com/tzafrir/human-in-the-loop
    claude --plugin-dir ./human-in-the-loop

    Loads the mod for one session only. Nothing is added to your settings.

How it works

hooks/register.tsx is the only hooks module. The assign_task handler checks the arguments, refuses duplicates and a sixth open task, stores the task and opens the pane. From hooks/register.tsx:

on('tool.call', { tool: ASSIGN }, async ($, e) => {
  if (e.agentId !== undefined) {
    return { deny: 'Only the main agent assigns tasks to the user. Say what you need from the user in your result instead.' }
  }
  const ask = parseAsk(e as unknown as Record<string, unknown>)
  if ('error' in ask) {
    return { deny: ask.error }
  }
  // ...
  return { result: assignedOf(task, active.length + 1) }
})

Tasks live in $.state and in one $.store key per session, under the project folder, written by a 60-second heartbeat so that a session that ended or went quiet can have its tasks taken on by the next one. Your responses are sent with $.prompt.submit when Claude is idle, or appended as a row with $.session.append while it works. A prompt.compose hook adds the steering text, and a prompt.context hook lists open tasks at the start and after a compaction.

Customize it

There are no options. You control it with the pane buttons and keys: d for Done, 1 to 4 for options, r to answer, x to reject, and Save for later or Send now for timing. Long answers go through your own prompt box: Long answer… starts it with ↳ Answer to #3:. To change limits, the constants MAX_OPEN and MAX_TITLE are in hooks/tasks.ts and BATCH_MS is in hooks/register.tsx.

Permissions & safety

We read every file the plugin loads before running anything: .claude-plugin/plugin.json, hooks/hooks.json, hooks/register.tsx, pane.ts, project.ts, tasks.ts, text.ts, the type declarations and the tests. There is no package.json, install script, bundled or minified code, or binary other than PNG and GIF images. There is a LICENSE file (MIT).

  • Network, processes, files, environment: none. A search of the hooks found no fetch, child_process, $.process, $.http, eval or dynamic import(). The only storage is $.store and $.state, with the data model described in docs/privacy.md. No telemetry; the author's privacy policy says nothing leaves your machine.
  • Daemons: none; a $.clock.every heartbeat runs only while the session does.
  • Model influence: this is the notable part. The mod adds three tools, a three-line section at the end of the system prompt (STEERING), a humanInTheLoop context block listing open tasks, and a digest of task updates attached to your next prompt. It also makes its three tools always visible instead of deferred. The text is plain and matches the README; we found no hidden or zero-width characters in the code or the manifest (only in emoji test strings).
  • Gating hooks: tool.call hooks answer only the mod's own three tools, and prompt.submit reads your prompt to recognize a long answer (↳ Answer to #N:) and to attach unsent responses. An answer that looks like a secret is dropped with a notice instead of being sent. Every other tool call passes through. validate notes that these hooks have no .catch.
  • Prompts it submits: your responses to tasks in your words, and one fixed line, I answered a task while you were finishing your reply; my answer is above.
  • Requirements: function hooks must be enabled in Claude Code (the README calls them early access). No external binary or account.

claude plugin validate passed with no errors and no warnings, and the author's tests passed: 192 pass, 0 fail, on Claude Code 2.1.310.

Intercepts tool calls
Sees every tool call Claude makes (tool.call / tool.check) and could block or change it.
Reads your prompts
Can see what you type and the conversation transcript (prompt.* / session.append / session.messages).
Changes the UI
Draws into the Claude Code interface: bands, panes, status text, toasts (ui.render / $.ui.*).
Adds commands/tools
Registers new slash commands or tools that you or Claude can invoke ($.command.register / $.tool.register).
Stores data
Keeps data between sessions in the plugin's private store ($.store.*).

Compatibility & troubleshooting

Checked with Claude Code 2.1.310 on macOS (validate, tests and the recording). If nothing happens:

  • Function hooks are enabled, and the plugin is loaded in /plugin.
  • You started a new session or ran /reload-plugins after installing.
  • Claude only assigns a task when the system prompt carries the steering text; it is not added in -p (print) or bare mode.
  • On a narrow terminal the pane is not opened unasked. Run /my-tasks, and click it or press ctrl+x tab to use the keys.
  • The mobile app draws no answer field, so there you only get Done, options and an immediate Reject.

FAQ

How is a task different from AskUserQuestion?
AskUserQuestion blocks Claude until you answer. A task does not: Claude keeps working while it waits, and your response reaches Claude as a message whenever you give it. The tool description tells Claude to use tasks for things it needs at some point in the session.
When does Claude hear my answer?
Right away if Claude is idle. If it is working, the answer is saved and goes when the turn ends, together with your other answers once no task is left open. The Send now button sends it at once, and the next prompt you type carries it too.
Do tasks survive /clear, a new session or a compaction?
Yes. Open tasks are kept in the plugin's own store, keyed by project folder, and the next session in that folder takes them on. Claude is told about them again at the start of a conversation and after a compaction.
What if I answer with a secret?
An answer that looks like a key, token or private key is held with a warning and not sent unless you press Send anyway. The tool description asks Claude to have you put a secret where it belongs and press Done instead of pasting it.
Does it send anything over the network?
No. We found no network, process or file-system calls in the code. It stores tasks with $.store and sends your responses to Claude only as prompts, in your own words.
Done Toast running in Claude CodeFeatured

Done Toast

A "Done in 2m 14s" toast and a short chime when a long Claude turn finishes, plus an optional desktop notification.

  • toast
  • Runs commands
  • Changes the UI
  • Plays sound

tested with v2.1.310

Next Steps running in Claude CodeFeatured

Next Steps

Two or three likely next prompts above the Claude Code input after each turn. Press 1, 2 or 3 to draft one.

  • above-prompt
  • Calls the model (uses your quota)
  • Reads your prompts
  • Changes the UI

tested with v2.1.291

More in Timers, todos, standups, Tools you add to Claude.