nasin pali (the way of work)
The code for this README exists, but requires some testing before release. I previously wrote a planning-mcp-server that I've kept some ideas from, and the overall workflow is about the same. I'm trying a CLI over MCP because MCP seems quite protocol-heavy for what could just be a few simple CLI invocations. Maybe connecting arbitrary data sources warrants a whole protocol like MCP, but I don't think something as basic as this does. Just some thoughtful design and prompting.
Usage
This section is first to entice you with nasin pali's simplicity; after installing the binary and prompt, having your coding tool using a better planning system just requires typing six (or fewer!) characters.
- When asking the model to do something a bit more complex, just append the
phrase
use np- If you want the model to
use npall the time, adjust the prompt after pasting to say something like always usenpinstead of any other todo tools.
- If you want the model to
- Once implemented, the
monitorsubcommand will show the model's plan and its realtime progress and theexportsubcommand will export the rendered plan and event log as Markdown. Should the model mark tasks failed/cancelled or change the goal/task content, it's required to provide a reason.
Installation
You need both the binary and the prompt.
The binary
- Using bin (highly recommended
because of centralised management/updates for statically-linked CLI tools like
this)
bin install goinstall://git.secluded.site/np@latest - Using the go toolchain (requires
tracking updates manually)
go install git.secluded.site/np@latest
The prompt
Paste this into some section of your ~/.config/AGENTS.md or
~/.claude/CLAUDE.md or whatever titled something like ## nasin pali (the way of work).
- Using
binIMPORTANT: If I ask you to `use np` or `use nasin pali` or some variation, you must completely ignore your built-in TODO tools and exclusively use what `np` provides. Try to use it, but if it's not in my PATH, ask me to install it with `bin install goinstall://git.secluded.site/np@latest`. If I've ask you to use it, start a session with `np s` and it'll guide you from there. If I haven't asked you to use it, proceed normally. - Using
go installIMPORTANT: If I ask you to `use np` or `use nasin pali` or some variation, you must completely ignore your built-in TODO tools and exclusively use what `np` provides. Try to use it, but if it's not in my PATH, ask me to install it with `go install git.secluded.site/np@latest`. If I've ask you to use it, start a session with `np s` and it'll guide you from there. If I haven't asked you to use it, proceed normally.
Overview
nasin pali, pronounced NAH-sin PAH-lee and installed as np, is a CLI tool
that encourages LLMs in agentic coding tools (specifically coding, I don't think
we want to support generic workflows) to do a bit more planning before going off
and making a bunch of changes. It is both meant for humans and LLMs; there are
subcommands that produce output for the model and subcommands for the human to
inspect the model's progress. There's a section on the name if
you're curious about it.
The todo systems built into agentic coding tools are often just that: todo and
nothing else. I think (backed by no evidence) that they do better when they can
also set a goal. If I understand the coding tools correctly, they also have the
LLM reproduce the entire task list with each todo_write invocation, which just
seems wasteful and careless to me. What if it decides it doesn't want to do a
task because it's "too hard" and it just omits that task next time it writes the
list? nasin pali helps force the model into a different overall flow.
Expected workflow
This is what I like, I'd be happy to hear of other workflows that lead to better/different success and to consider whether nasin pali can support them
The operator is expected to load the prompt up with relevant text. Type the issue in the prompt, paste the bug report, tell it how to fetch the issue from your issue tracker, whatever you like. If the issue content is too sparse, make sure to add more context. The more context you give and the higher its quality and relevancy, the better results you'll have. Include paths to as many files you know will be relevant as possible. Mention particular symbols, paste snippets of code, etc. Once your prompt looks good, send it off.
In the np section of the model's rules, we'll have instructions to
immediately run start a session if the operator says to use np or something
similar. Each command further in the flow reveals the next step as instructions.
np s tells the model to set an overarching goal with np g s -t title -d description that captures the operator's request, combining the information
from the ticket and any extra operator-provided context. If there's a ticket ID,
that goes in the goal description. The output of np g s says to look at the
provided references, thoroughly consider how to go about resolving the goal, and
gather additional context from other files if necessary. Once it has a good idea
how to resolve the goal, it should add some tasks with np t a -t title -d description -t title2 -d description2. The descriptions are good places to
reference files and symbols. The output of np t a tells it to update tasks as
it works on them with something like np t u -i task-id -s status.
Commands that modify the model's goal or list output the full changed plan
(formatted like so) so it doesn't have to run
another command to check, obviating patterns like git status after every git commit. It can use np p to check the plan (goal, desc, remaining tasks,
descs) and use np t -s status to filter to pending, in progress,
completed, all, etc. tasks, but usually doesn't need to because we
immediately show it after every modification.
Resume an interrupted session in a new context window by telling the model to
run np r. This outputs the full plan, provides relevant usage instructions,
and tells the model to "check above" for a bug/issue/ticket ID in the goal
description. If present, read that. Then read the files/symbols referenced in
the pending tasks to get a good idea of what work is left.
Once finished, the operator or model (I'm not sure which yet, see next section)
archives the session with np a.
Details
Session scoping
Each session is working-directory-scoped so neither the model nor the human
have to provide a session ID or something for each invocation like np s -s session-id -t title -d description. This is why there are np s and np a
commands for starting and archiving a session. There can only be one session
in progress per directory, so worktrees allow for parallel sessions.
I'm unsure who should archive the session. I like the idea of requiring the operator to, meaning we can leave that bit out of the model's rules, but maybe the coding tool has no way for the operator to execute shell commands. In that case, they'd have to type the whole thing to the model or quit/open a new shell to archive themselves before the model can start a new session. Maybe telling the model about the archival command, but to never run it without explicit instruction from the operator, would be sufficient.
Global database with events
Sessions, plans, goals, tasks, everything is stored in a shared
Badger database in
$XDG_CONFIG_HOME/nasin-pali/.
Every LLM-oriented sub-command is tracked as an event. Sub-commands that do anything to modify either created tasks or set goals require a reason ("operator said so" is insufficiently detailed, but otherwise acceptable) to go with those events.
Event rendering
The interactive, human-focused sub-commands (for now, just m for monitor),
are for watching the events and the resulting list as they change in
real-time-ish. The goal and description and tasks and their descriptions are
rendered at the top of the UI and updated based on database events using some
Charm libraries. Change events are underneath the rendered state, sorted most
recent (top) to least recent (bottom).
This will probably be implemented later, once the LLM-oriented planning commands are solid and I see regular success with them.
The format the model sees
It uses individual unicode symbols to represent task statuses. This costs one
token per status where more verbose checkboxes - [x] or words completed
might use more. The failed icon (☒) and cancelled icon (⊗) are only shown in
the legend if there are actually failed or cancelled tasks in the list.
Create a comprehensive MCP server for task planning and management
Legend: ☐ pending ⟳ in progress ☑ completed
☑ Set up project structure [a1b2c3d4]
Create Go module, directories, and basic files
⟳ Implement core planning logic [e5f6g7h8]
Create Goal and Task data structures with deterministic IDs
☐ Build MCP server integration [i9j0k1l2]
The name
Is from toki pona, a simple language, and pronounced NAH-sin PAH-lee. nasin occupies the semantic space of "method, doctrine, tradition; path, road, way" while pali covers "work, activity; create, build, design; put effort toward, take action on". Together and in this context, nasin pali could be translated as "the way of work", "the doctrine of design", etc.
Random thoughts
-
When providing multiple lines for the body, use
np g s -t "Sentence case title" -d "$(cat <<'EOF' Multi-line - Body - Here EOF )"