<!--
SPDX-FileCopyrightText: Amolith <amolith@secluded.site>

SPDX-License-Identifier: CC0-1.0
-->

# nasin pali (the way of work)

[![REUSE status](https://api.reuse.software/badge/git.secluded.site/np)](https://api.reuse.software/info/git.secluded.site/np)
[![Go Report Card](https://goreportcard.com/badge/git.secluded.site/np)](https://goreportcard.com/report/git.secluded.site/np)

_Upgrade your coding tool's todo system_

The software this README describes exists in the `dev` branch, but requires
some testing and polish before I'm willing to merge it into `main` and cut a
"real" release.

## Usage

This section is first to entice you with _nasin pali_'s simplicity;
after installing [the binary](#the-binary) and [prompt](#the-prompt),
having your coding tool use a better planning system (or any planning
system at all if you use [Crush](https://git.secluded.site/crush)) just
requires typing six characters max.

- When asking the model to do something a bit more complex, append the
  phrase `use np`
  - If you want the model to `use np` _all_ the time, adjust the prompt
    after pasting to say something like _always use `np` instead of any
    other todo tools_.

**NOTE:** _nasin pali_ is not meant to replace your existing ticket
tracker. Keep using GitHub issues or [todo.sr.ht](https://todo.sr.ht) or
[git-bug](https://github.com/git-bug/git-bug) or whatever else.  _nasin
pali_ instructs your model to record the issue reference (as well as any
file references) so you can easily resume the session in a new context
window without having to provide all the information again.

## Installation

You need both the binary and the prompt. If you don't have the binary
when the model tries to start a session, it's instructed to ask you to
install it using the appropriate command.

### The binary

- Using [bin](https://github.com/marcosnils/bin) (highly recommended
  because it's one tool to manage and update myriad CLI tools
  distributed as statically-linked binaries, like _nasin pali_)
  ```bash
  bin install goinstall://git.secluded.site/np@latest
  ```
- Using the [go toolchain](https://go.dev/dl) (requires tracking updates
  manually)
  ```bash
  go install git.secluded.site/np@latest
  ```

### The prompt

Paste this snippet into some section of your `~/.config/AGENTS.md` or
`~/.claude/CLAUDE.md` or whatever titled something like `## nasin pali
(the way of work)`.

- Using `bin`
  ```markdown
  IMPORTANT: 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 directly, but if it's reported unavailable or 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`. If I haven't asked you to use it, proceed normally.
  ```
- Using `go install`
  ```markdown
  IMPORTANT: 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 directly, but if it's reported unavailable or 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`. 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](#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.

I previously wrote a
[planning-mcp-server](https://git.secluded.site/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.

## 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](#the-format-the-model-sees)) 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 `s`tarting and `a`rchiving 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](github.com/hypermodeinc/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 `m`onitor),
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](https://tokipona.org/), _a simple language_, and pronounced
_NAH-sin PAH-lee_. [_nasin_](https://nimi.li/nasin) occupies the semantic space
of "method, doctrine, tradition; path, road, way" while
[_pali_](https://nimi.li/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

  ```bash
  np g s -t "Sentence case title" -d "$(cat <<'EOF'
  Multi-line
  - Body
  - Here

  EOF
  )"
  ```
