Clone

git clone git@git.secluded.site:np.git

README

nasin pali (the way of work)

REUSE status Go Report Card

This README is aspirational! None of the code exists yet, I'm just getting my ideas down. I previously wrote a planning-mcp-server that I'll keep 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.


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
    )"