Skip to main content

Multi-Agent Prompt ✍️

A crash-proof, autosaving prompt editor for AI coding agent CLIs.

Chat text boxes lose long, carefully-composed prompts to a single wrong keystroke, and give you almost no editing power while you write. multi-agent-prompt moves composition out of the chat box entirely: write in a real Neovim, in a split pane next to your agent session, autosaved to disk every couple of seconds so a crash or a fat-fingered shortcut can never cost you more than a moment of typing. When you're ready, hand it to the agent with /prompt — which reads it, archives it, and clears the file in one step, so there's no separate "now go clear it" to remember.


Install

pip install multi-agent-prompt
# or
uv tool install multi-agent-prompt

Requires Neovim — the autosave hook is Lua, so plain Vim isn't supported.

Usage

Open a split pane next to your agent CLI (Windows Terminal: Alt+Shift+-; tmux: <prefix> ") in the same working directory, then run:

map

This opens .ma/prompt/current.md — resolved to the current project's git root, so every pane in the same repo shares one scratch file — in your actual nvim, your actual init.lua, your actual keymaps and plugins. No config import step, no reimplemented Vim subset: it's just Neovim. You land in insert mode already, cursor at the end of the buffer, so there's no i to press before you start typing (--no-insert if you'd rather open in normal mode). A buffer-local autocmd (scoped only to this one buffer — it never touches how you edit anything else) autosaves ~2 seconds after you stop typing, and immediately when you switch away from the pane (FocusLost/BufLeave), so the save always beats you to the chat window.

When you're done, switch back to the agent pane and either:

  • Type /prompt (if the agent's install includes the skill — see below) — reads the draft, archives it, and clears the file, all in one step, or
  • Reference @prompt.md / @.ma/prompt/current.md directly, if your agent supports file mentions and can see gitignored files — this is a plain read, so unlike /prompt it doesn't archive or clear anything.

Pasting a long CLI transcript or diff in? Anything 6 lines or more (bracketed paste, "+p, "*p — any paste source) auto-folds, closed, so it doesn't bury the rest of what you're writing — za/zo/zc (standard Vim) toggle it open.

Also want to browse past drafts without leaving the editor? A buffer-local keymap — <leader>ph by default — lists archived drafts (newest first) in a split; <CR> opens one, read-only. Forgot what any of this is bound to? Press g? — it shows exactly the keymaps active for this session (respecting any --clear-key/--history-key overrides, and omitting whichever ones you disabled):

map            # open the scratch file (same as `map edit`)
map where      # print the resolved file path
map show       # print its current content to stdout (does not clear it)
map pop        # print it, archive it, and clear it — what /prompt uses
map clear      # archive the current draft, then empty it, without printing it
map --clean    # skip your init.lua entirely (-u NONE) for faster startup
map edit --clear-key '<F5>'      # rebind the in-editor clear keymap
map edit --no-clear-key          # don't register it at all
map edit --history-key '<F6>'    # rebind the in-editor history-browse keymap
map edit --no-history-key        # don't register it at all
map edit --help-key '<F1>'       # rebind the in-editor g? cheatsheet keymap
map edit --no-help-key           # don't register it at all
map edit --fold-threshold 3      # auto-fold pastes of 3+ lines instead of 6
map edit --no-fold-paste         # don't auto-fold pastes at all
map edit --no-insert             # open in normal mode instead of insert mode
map clear --keep 20              # override how many archived drafts to retain
map clear --no-archive           # discard instead of archiving (e.g. it had a secret in it)

map pop accepts the same --keep/--no-archive as map clear.

The archive

map pop/map clear — from the CLI or the in-editor keymap, which shells out to map clear — never actually discard a non-empty draft; they move it to .ma/prompt/archive/<timestamp>-<seq>.md first, then prune that archive down to the most recent entries. Pruning is by count, not age (--keep / MAP_ARCHIVE_KEEP env var, default 10) — simpler to reason about than a retention window, and it doesn't depend on the clock. Use --no-archive for the one case that shouldn't be kept anywhere: you pasted a secret and want it actually gone.

Performance

A map session opens your entire Neovim config, which is exactly the point — but if that config is large, startup isn't free. Two things worth knowing, from actually measuring it (not guessing):

  • It's not a one-time thing. Whatever makes your first map slow will make every subsequent one about equally slow, unless something changes (lazy.nvim itself finishes installing/compiling once; LSP servers and large plugin trees generally don't get meaningfully faster after that).

  • On WSL specifically, check for vim.opt.clipboard = 'unnamedplus' (or similar) in your own init.lua. Setting that option makes Neovim probe for a clipboard provider immediately, and on WSL that probe walks every PATH entry checking executable() — including everything under /mnt/c/..., which is slow cross-filesystem interop. Measured on this project's own dev machine: ~900ms startup with that line in play, ~160ms with the Windows PATH entries stripped, ~4ms with -u NONE. That's not multi-agent-prompt overhead; it's one line in a personal init.lua interacting badly with WSL, and fixing it (or guarding it — see MAP_SESSION below) speeds up every Neovim session, not just map.

  • map --clean (-u NONE) sidesteps all of it by skipping your config entirely — the built-in fast path when you don't need your plugins for a quick edit.

  • MAP_SESSION=1 is set in the environment of every nvim map launches. Nothing in this package reads it — it's there so you can guard an expensive line in your own init.lua behind if not vim.env.MAP_SESSION then ... end, if you want full-config speed back without giving up faster map startup. That's your config to edit, not something this tool does for you. This isn't just for the clipboard line above — a scratch prompt buffer has no use for a file-tree sidebar or git tooling either, and with lazy.nvim you can skip those specific plugins the same way, with cond on the spec:

    return {
      'nvim-neo-tree/neo-tree.nvim',
      cond = not vim.env.MAP_SESSION,
      -- ...
    }
    

    Confirmed on this project's own dev config: with neo-tree.nvim and gitsigns.nvim guarded this way, <leader>e (NeoTree's toggle) becomes a no-op in a map session, and their entire module trees (dozens of individual require() calls each) simply don't load — real startup savings, not just fewer keymaps to trip over. cond is evaluated on every start, so this takes effect immediately; no :Lazy sync/restart needed.

  • It's specifically a startup cost, not a per-save one. The clipboard probe runs once, while your init.lua is sourced, not again on autosave, on FocusLost, or when you switch panes and type /prompt — that last step never touches nvim at all (map pop/reading the file is a separate, plain filesystem read and write). If a session still feels slow at the hand-off moment specifically, that's terminal pane-switching or the agent's own slash-command overhead, not this tool or Neovim.

  • /prompt's own overhead is small, and it isn't Neovim's. Measured on this project's own dev machine: map pop runs in ~60-85ms end to end — bare python3 -c pass alone is ~30ms of that, this package's own imports add maybe another ~20ms, and the rest is the file read/archive/write. If /prompt still feels slow, that latency lives in the agent host's own tool-call round trip (spawning/sandboxing the shell command), not in anything this package does — there's no nvim process in this path at all. The one thing the prompt skill itself controls: it runs map pop directly rather than checking which map first, since that check is a second subprocess spawn that's a wasted round trip almost every time.

Agent integration

skills/prompt/ is a portable Agent Skill that teaches a host to read .ma/prompt/current.md and treat its content as the user's message when they type /prompt. See skills/README.md for install paths.

Why not tmux send-keys / auto-injection?

That's the obvious next step — save, close the pane, and have the tool type /prompt into the neighboring agent pane for you — but it needs a reliable way to identify which pane is running the agent, which varies by terminal (tmux panes, Windows Terminal panes, and OS-level input injection like xdotool/wtype all solve a different half of that problem). The manual handoff above works everywhere today; auto-injection is being explored as a follow-up, potentially building on multi-agent-registry's chat discovery to identify a live agent session (not just a recent one) in the same directory.

If/when that lands: prefer sending a widely-supported "submit" keystroke — Ctrl+Enter is the closest thing to a universal convention across chat input boxes — into the target pane after typing /prompt, over anything input-method-specific, so the same injection code has a chance of working across agents rather than being re-tuned per host.

Design notes

  • The prompt file is per-project, not global. .ma/prompt/current.md resolves against the nearest .git root, so working on two projects in two terminal tabs never mixes up their scratch files.
  • .ma/ is a shared root, not this tool's alone. It's the umbrella directory for the whole multi-agent-* line (map's CLI alias is the shared ma prefix of map/mar/maa) — one dotfolder instead of one per product. Only .ma/prompt/ is this tool's; a sibling product could use .ma/registry/, etc., without colliding. Note that task-agent's existing .task-agent/ convention predates this and stays as-is — migrating an already-shipped tool's config layout is a separate, larger decision.
  • .gitignore is managed for you. The first time map edit runs in a git repo, it appends .ma/prompt/ to .gitignore if it isn't already covered — including by a broader pre-existing .ma/ entry.
  • Reading is non-destructive; handing off isn't, but it never discards either. map show and @prompt.md (file mention) just print/read — the file is untouched either way. /prompt (map pop) clears it, because the whole point is not needing a separate "now go clear it" step — but it archives first, so "cleared" never means "gone". --no-archive is the explicit opt-out for content that shouldn't be kept anywhere at all.
  • The editor notices when the file changes out from under it. /prompt runs map pop from the agent's process, not from inside the running nvim session — so if you're still looking at that buffer when you hand a draft off, it auto-reloads (autoread + checktime on FocusGained/BufEnter) the next time you focus it, rather than keep showing the text you already submitted. It won't discard anything you've since typed there unsaved.

Release files for multi-agent-prompt 0.1.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 multi-agent-prompt 0.1.0
File Size Uploaded
multi_agent_prompt-0.1.0.tar.gz 50.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for multi-agent-prompt 0.1.0
File Interpreter ABI Platform
multi_agent_prompt-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 68.9 kB

Release files / multi_agent_prompt-0.1.0.tar.gz

Download URL multi_agent_prompt-0.1.0.tar.gz
Size 50.7 kB
Tags Source
SHA-256 checksum
How to use checksums
33da4379cb47cba570dc8ff64e13bd4b4030e45bfe490884f0f47ac798ccf0d0
BLAKE2b-256 checksum
How to use checksums
3905f77a0205ac0f10f681bb2ac033b49bf0de2995e05d3e4f726840c895a820
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 12, 2026.

Transparency log

Release files / multi_agent_prompt-0.1.0-py3-none-any.whl

Download URL multi_agent_prompt-0.1.0-py3-none-any.whl
Size 18.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8e688e2e4a1effd220b1ea6eeb6150bd92b80680995a752e56c36f4cb9ab33ed
BLAKE2b-256 checksum
How to use checksums
d5c5ca4961bc29ac45b0d4b01dbcf28ba700d13da978f61b548c6a59cc16b103
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 12, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

This release

0.1.0 This release

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