Skip to content

About

A private AI assistant that runs entirely on your own machine. One Go binary: local models, memory that learns from your files, and nothing leaving the machine unless you say so. Made by PN Scripts

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

PN Scripts Assistant

CI Licence: MIT Go

PN Scripts Assistant is a PN Scripts product (product page).

A personal, self-learning AI assistant that runs entirely on your own machine.

One binary. No database server, no container runtime, no cloud account. It remembers what it learns about you, and what it learns stays here.

What it does

  • Answers with memory. It recalls what it already knows about your projects and documents, and uses that to answer — so "where does that project live" gets a real path rather than a guess.
  • Learns on its own. It scans your code and documents, and proposes things worth remembering after conversations. Anything it inferred waits for you to approve; anything it can verify against the disk promotes itself.
  • Acts. It can read files, list directories, run commands, search and read the web, and control a smart home. Out of the box it does what you ask without stopping to confirm each step — and everything it does is written down, and a file it changed can be put back. If you would rather be asked, the Permissions panel has three settings: ask every time, ask about what you have not already allowed, or act freely.
  • Draws what it knows. The interface renders a live map of memory, built from real embedding similarity — not decoration.
  • Listens and speaks. Conversation mode hears you until you stop talking, answers, reads the answer aloud, and listens again. Both halves are local.
  • Hires and equips experts. "Hire a game-development expert", "hire an electrician to help me plan this installation": it proposes who, what they may and may not touch, what the machine needs (with size, source, licence and cost), and who else is needed — and hires nobody until you say so. Advisory and regulated work never touches anything, and says which licensed person takes over.
  • Starts and builds projects. "Make me a Tetris game" asks where, chooses the engine from what you asked and what this machine can really do, and shows the whole plan. Once you approve, the work is confined to that folder — by the kernel, not only by checking arguments — its settings live in .pn-assistant/ beside the code, and it is finished only on fresh evidence: the latest check passed after the last change, a run that did not fail, a picture that shows something.
  • Chooses how work is done. Who writes the code — Claude Code or Codex on your subscription, or a model on this machine — is decided per piece of work, subscriptions first, switching before a limit is hit and falling back when a service is signed out or out of allowance, with every decision and switch recorded. How much of a subscription is left is shown only when its service says. Checking, running and building are this program's own work with the engine, never a model's word. See ADR 0005.
  • Integrations, gated. MCP servers, approved one by one, granted per agent and per project, confined to their own folders, with every call recorded. See ADR 0004.

Privacy

Out of the box everything is allowed, and everything is recorded. Its owner asked for that (ADR 0007), and an install that predates it is switched over once, on upgrade. The strict settings are still in the code and one line away in brain.conf.

mode what leaves the machine
open (default) your messages, the memory recalled for that turn and your profile go to the hosted provider you chose; the web may be read
research search queries only; conversations and memory stay here
private nothing — local model, local embeddings, no web
setting default what it does
BRAIN_FREEDOM everything nothing is asked before it acts (granted and ask still exist)
BRAIN_CONFINE 0 0 lifts every limit below; 1 puts all of them back
work privacy (resources/policy.json) cloud_preferred Claude Code, Codex and hosted models are preferred for project work

With BRAIN_CONFINE=0 and freedom everything, none of these stop or ask: installing software or a model, sending mail, a permanent hire, switching an integration on (switching it on approves it), project work outside its folders or the kernel sandbox around it, a hire's tool list, an integration granted to somebody else, protected files such as keys and mail folders, and addresses on this machine or the local network. Claude Code runs with --dangerously-skip-permissions and Codex with --dangerously-bypass-approvals-and-sandbox.

What is kept: a tool its owner refused by name stays refused, what he switched off (BRAIN_TURNED_OFF) stays off, and every tool call is still written down with what it was given and what came back. Files it overwrites are still kept so they can be put back.

What that means: in open mode your messages, the memory recalled for a turn and profile.md are sent to the hosted provider you chose; the memory database itself stays on your machine. With nothing confined, a web page the assistant reads can try to talk it into reading a key and sending it somewhere, and nothing stops to ask. Set BRAIN_CONFINE=1 (or privacy to private) on a machine where that matters.

What it keeps about you is encrypted at rest so that only this program can read it (ADR 0008): conversations, memories and their embeddings, the record of every tool call, reminders, tasks, the profile, the voiceprint, integration credentials, the secrets and your name in brain.conf, and the log — AES-256-GCM with a key kept in this computer's keyring (Secret Service, DPAPI or Keychain; a 0600 key file where there is none). The first time, you are shown a recovery key once: the brain's drive travels and the key does not, and on another computer the brain opens only with it. This protects the drive, copies and backups, other users and other machines; it does not protect against a program running as you, which can ask the same keyring.

Root is asked for, not taken: run_as_admin has the system show its own password dialog (polkit, UAC, the macOS prompt) each time.

An unrecognised privacy value is still treated as private, because the safe reading of a typo is the strict one.

Everywhere it connects to on its own is written down, with a reason beside each entry, in clients/internal/outside/outside.go — and a test reads the whole program and fails if an address is written into it that is not on the list. That list documents; it blocks nothing at run time. There is no telemetry and nothing reporting to this project. Addresses its owner asks for — a page, a mail server, an integration — are his and are not listed.

Requirements

  • Ollama with a chat model and nomic-embed-text
  • For the native window: libwebkit2gtk-4.1-dev and libgtk-3-dev (Linux)
  • For speech: any of speech-dispatcher, espeak-ng, or piper
  • For listening: whisper.cpp with whisper-cli on your PATH and a model of 50MB or more

None of it is required. The assistant reports what it cannot do rather than refusing to start, and controls for capabilities that are missing are not shown at all. The first run checks for all of this and offers to install what it can — the package does not carry a separate checker, because the program is one.

Two Ollama settings worth checking

Ollama's own defaults work against this, and both need root to change:

OLLAMA_HOST=127.0.0.1:11434   # not 0.0.0.0 — see Privacy below
OLLAMA_MAX_LOADED_MODELS=2    # or every reply reloads the chat model

The second is not a preference. Recall embeds your question before every reply, and with only one model permitted in memory, loading the embedder evicts the chat model — which is then read back from disk to answer. Measured on a 7B model: 6.8 seconds to reply when it is resident, 15.8 after an embedding evicted it.

The first matters more. This brain binds to loopback and refuses to do otherwise, but it sends every conversation and every recalled memory to Ollama. An Ollama on 0.0.0.0 is unauthenticated and reachable by anything on your network, which undoes the careful part.

Installing it

On Ubuntu it installs as a package and draws its own window. On macOS and Windows it installs the way those systems expect and shows its interface in your browser — the native window is Linux-only so far, and that is the only difference between them.

System Download
Ubuntu / Debian pn-scripts-assistant_<version>_amd64.deb sudo apt install ./…deb
macOS 11+ …-macos-arm64.dmg (or amd64 for Intel) drag it to Applications
Windows 10+ …-windows-setup.exe run it; no administrator password

Nothing is signed — there is no Apple developer account and no Windows certificate behind this — so macOS and Windows both refuse the first open and both take one extra click to pass. installing.md says exactly which click, for each.

On Ubuntu

Ubuntu 24.04 or newer, on a 64-bit machine. Download pn-scripts-assistant_<version>_amd64.deb from the releases and:

sudo apt install ./pn-scripts-assistant_*.deb

apt pulls in the libraries the window needs — the package says which ones, having been asked of the binary rather than remembered — and puts PN Scripts Assistant in the applications menu with its icon.

To check what you downloaded is what was built:

sha256sum -c SHA256SUMS

Checking that a download is genuinely ours

A checksum proves a file matches a published number. It does not prove the number came from here — so every released file also carries a provenance attestation: a statement, signed by GitHub with a key nobody here holds, binding that file to this repository, the workflow that built it and the commit it was built from. Check any download with nothing installed but the GitHub CLI:

gh attestation verify pn-scripts-assistant_*_amd64.deb --repo pnscripts/pn-scripts-assistant

Nothing is signed with a code-signing certificate — an Apple one and a Windows one cost money every year and identify a company, and this project has neither. That is why the attestation is here: it is free, it needs no secret, and it is the one form of "this really is the file that workflow built" that can honestly be offered. SECURITY.md says the same and what else is not there yet.

Building the packages yourself

make release

That formats, vets, runs every test, builds the .deb, checks it from the outside with lintian, and writes SHA256SUMS beside it in build/packages. It needs libgtk-3-dev, libwebkit2gtk-4.1-dev, dpkg-dev, fakeroot and (for the check) lintian.

Or just the binary, without a package:

CGO_ENABLED=1 go build -C clients -trimpath -o ../build/pn-scripts-assistant ./cmd/pn-scripts-assistant

CGO_ENABLED=0 builds too — you get the assistant without a native window, reachable in any browser at 127.0.0.1:8790.

Running it

Press the Ubuntu key, type the first few letters of its name, and press Return. The first run opens setup: it finds Ollama, offers to install a model, and asks where the brain should live.

From a terminal, the same thing:

pn-scripts-assistant

If it is already running, that brings the existing window forward rather than starting a second copy — one assistant per brain, and the second says where the first is answering. pn-scripts-assistant serve runs it without a window, for a machine with no desktop; the address is printed when it starts.

A few things worth knowing:

Which copy is this pn-scripts-assistant version
Everything it can do from a terminal man pn-scripts-assistant
Where the data is, and how much pn-scripts-assistant status
Why it did not start ~/.local/state/pn-scripts-assistant/logs/pn-scripts-assistant.log
Somewhere else BRAIN_ADDR=127.0.0.1:9000 pn-scripts-assistant

Everything else is in the window. The terminal is for people who prefer one.

Updating and removing it

A newer package installs over the old one and keeps everything learned:

sudo apt install ./pn-scripts-assistant_<newer>_amd64.deb

Removing the program leaves the brain alone, deliberately — years of somebody's memory should not go with an apt remove:

sudo apt remove pn-scripts-assistant          # the program
rm -rf ~/.local/share/pn-scripts-assistant    # and the memory, if you mean it
rm -rf ~/.config/pn-scripts-assistant ~/.local/state/pn-scripts-assistant

If the brain was moved to another drive, pn-scripts-assistant status says where it is before you remove anything.

Where the data lives

The brain finds itself. It looks for a .brain-root.json marker across mounted drives, so the data can live on an external disk, be unplugged, reattached at a different path, or moved to another computer — nothing is pinned to a machine. With no marker anywhere, it creates one under ~/.local/share/pn-scripts-assistant/data. A brain made before the program was renamed from PN Brain stays where it was, in ~/.local/share/pn-brain, and is still found there.

Settings live beside the data in brain.conf, not beside the program, because they describe this brain rather than this installation.

Talking to it

Type in the box, or use your voice. Three controls appear in the Engine panel, and only when the machine can actually do them:

  • Microphone — which input to listen through. Worth setting: the system default is often an empty analog jack rather than the microphone you own.
  • Read replies aloud — answers are spoken as well as shown.
  • Conversation mode — listens until you stop talking, answers, speaks, and listens again, until you switch it off.

Silence detection calibrates to your room at the start of every turn, because a fixed threshold is either deaf in a quiet room or triggered by a fan in a noisy one.

Spoken turns can use the same tools as typed ones, under the same permission setting. What was said decides whether tools are offered, not how it arrived: small talk is answered without them either way. Under the default act freely setting a spoken request can change something without stopping to ask, and is recorded like any other; set Permissions to ask if you would rather confirm.

If it does not hear you, pn-scripts-assistant mic-test reports the three numbers that make that answerable: your room's noise floor, what therefore counted as speech, and how loud you actually got.

Speed, honestly

On a CPU with no GPU this is slow, and the shape of the slowness is worth knowing. Measured on four cores with a 7B model: prompts are processed at about ten tokens a second and answers generated at two and a half. Prompt size is therefore very nearly the whole reply time.

A turn answered without tools, which is most small talk and much of what is said aloud, takes around 40 seconds. A turn that needs tools takes longer, spoken or typed, because tool schemas add roughly 530 tokens to the prompt. Trimming what is sent helps and has limits; the floor is the hardware. A GPU, or open mode with a hosted model, are the only things that change the order of magnitude. In open mode your messages and the memory recalled for that turn are sent to the hosted provider you chose; the memory database itself stays on your machine.

Commands

The interface does everything; these exist for people who prefer a terminal.

pn-scripts-assistant                    run the app: serve, and open the window
pn-scripts-assistant serve              serve only, without a window
pn-scripts-assistant status             where the data lives and what is in it
pn-scripts-assistant ingest <dir>...    learn about the projects and documents in a folder
pn-scripts-assistant ingest --browser   learn which websites you use (domains only, never URLs)
pn-scripts-assistant promote            turn validated lessons into durable knowledge
pn-scripts-assistant tidy               clear what is not worth remembering out of the queue
pn-scripts-assistant mic-test           listen once and report what the microphone heard
pn-scripts-assistant drives             where the brain could live, and how much room is left
pn-scripts-assistant move <dir>         move the brain to another drive, verifying every byte
pn-scripts-assistant rewrite-paths      repair stored paths after a move, then re-embed
pn-scripts-assistant copies             where copies of the brain are kept, and copy now
pn-scripts-assistant places             the drives and folders it learns from  (--read)
pn-scripts-assistant menu               put it in the applications menu  (--remove to take it out)
pn-scripts-assistant setup              choose the drive, the model and the keys again
pn-scripts-assistant version            which copy of the program this is

man pn-scripts-assistant has all of them, with the files and the environment variables.

How it is built

Go, and a SQLite file. Vectors are stored as float32 blobs and similarity is computed in process — exact, and fast enough at this size that an index would be a dependency bought for nothing.

Nothing else has to be running for it to start: no database server, no container runtime, no background stack. The program, one file of memory, and whichever model you point it at. How it came to be built this way is in docs/ROADMAP.md.

The rest of it

Installing, updating, removing the package and what it puts where
Setting it up the first run, privacy, environment
Models which one answers, and why the second question is faster
When something is wrong the log first
Working on it building, tests, expectations
Making a release make release
What changed between versions, in the terms you would notice
Decisions why things are the way they are
Audits what was measured, and when
Security the trust model, how to report a fault, and what is honestly not there yet
Contributing what a change is expected to carry
Code of conduct short, because a long one would not be read

How this project checks itself

Stated here because "trust me" is not a thing a program that reads your files gets to say.

  • Every push and every pull request runs formatting, go vet, the whole test suite under the race detector, a build for each system it claims to build for, govulncheck, and the .deb put through lintian — ci.yml.
  • Every released file is built by a workflow on the system it is for, is published with its SHA-256, and carries a signed provenance attestation anybody can check.
  • The package is reproducible. The same commit built on a GitHub runner and on the maintainer's desktop produces a byte-identical .deb, so you can check out that commit, run make package, and compare — rather than trusting a published number.
  • Every action in CI is pinned to a commit, not to a tag somebody could move, and only the job that publishes a release can write anything.
  • main requires those checks to have passed, and refuses force-pushes and deletion.
  • The audits in docs/audit/ use a fixed vocabulary — VERIFIED, IMPLEMENTED — NOT VERIFIED, BROKEN — so what was measured is distinguishable from what was merely written. They are the maintainer's own; nobody independent has audited this, and that is said rather than left to be assumed.
  • Three dependencies, each with a reason written down, and no new one without another.

Licence

MIT — see LICENSE. Yours to read, run, fork and sell.

About

A private AI assistant that runs entirely on your own machine. One Go binary: local models, memory that learns from your files, and nothing leaving the machine unless you say so. Made by PN Scripts

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages