Skip to content
Back to skills

Pin

ASecurity

Pin a constraint for the rest of this run, shown on every prompt; use when a rule ends with the task, and remember for anything durable.

  • 3 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 19, 2026
ai-agentsgoshellbashnodeexpress

Works with

  • claude code
  • cli

Security analysis

A100/100

Scanned September 19, 2026

npx -y skills add mubit-ai/plugins --skill pin --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Pin?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Pin
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mubit-ai-pin/badge)](https://www.skillsdirectory.com/skills/mubit-ai-pin)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: pin
description: Pin a constraint for the rest of this run, shown on every prompt; use when a rule ends with the task, and remember for anything durable.
disable-model-invocation: false
allowed-tools: ["Bash(node ${CLAUDE_PLUGIN_ROOT}/bin/pin.mjs:*)"]
---

**This skill never installs anything.** It runs one Node process from the plugin directory,
which writes a run-scoped variable to the user's own Mubit instance. No packages, no services,
no changes to the shell.

## What a pin is

A pin is a sentence that is true for **this run and this task**, injected in full above the
recalled memory on every prompt until it is cleared.

> for the rest of this, don't touch the vendored server

The model is who notices a sentence like that. Before pinning existed, the only place to put
it was memory — so it was written as a *lesson*, and a lesson is durable and cross-session. It
would then be recalled into every future session of a project where it had long since stopped
being true. Removing that failure is the entire reason this command exists.

## Pin or remember — the line is not blurry

| | `/mubit-memory:pin` | `/mubit-memory:remember` |
| --- | --- | --- |
| Scope | this run, this task | durable, every future session |
| Ends when | the user clears it, or the run does | never, unless it is forgotten or superseded |
| Costs | tokens on **every** prompt of this run | nothing until recall decides it is relevant |
| Example | "no new dependencies while we finish this PR" | "this project pins dependencies by exact version" |

Read the two example rows before choosing. If the sentence would still be worth saying in six
months, in a different session, it is a lesson — use `/mubit-memory:remember`. If it would be
wrong to say next week, it is a pin.

## Pin something

```bash
node "${CLAUDE_PLUGIN_ROOT}/bin/pin.mjs" add "don't touch the vendored server" --data-dir "${MUBIT_CC_DATA_DIR:-${CLAUDE_PLUGIN_DATA}}" --run <run_id> --json
```

It renders on the very next prompt — the command writes through to the local cache the recall
hook reads, so there is nothing to wait for.

Use the user's own words. A pin is an instruction, and paraphrasing an instruction changes it.

### Always pass `--run`

`<run_id>` is the run named in the **Mubit memory is active** block at the top of this
conversation — the line reading `Run: cc-<slug>-<hash>`. Copy it verbatim.

Without `--run` the command has to guess, and it guesses by reading whichever run's hooks fired
most recently. Every Claude session on the machine shares one plugin data directory, so a
second session answering a prompt in the seconds before you type wins that race, and the pin
is written to *its* run. The command reports success either way. The user then watches for a
pin that renders in a session they are not looking at.

The command now refuses rather than guessing when two runs are live (`ambiguous_run` below),
but do not rely on that: it can only see the sessions whose hooks happen to have fired inside
its window, and passing `--run` is what makes the question not arise.

### And always pass `--data-dir`

**`--data-dir "${MUBIT_CC_DATA_DIR:-${CLAUDE_PLUGIN_DATA}}"` is not optional.** A Bash tool
call does not inherit `CLAUDE_PLUGIN_DATA` — it arrives empty — so without the flag the command
has to guess which of several `mubit-memory*` directories the host is using, and either
refuses with `no_run` or writes the pin through a store this session's hooks never read. The
host substitutes `${CLAUDE_PLUGIN_DATA}` into this file before you read it, and the shell
default around it lets a session that pins `MUBIT_CC_DATA_DIR` keep its pin — the same order
every hook resolves in. Pass the whole expression straight through. Do not turn it into an
`ENV=… node …` prefix: that is no longer a `node` command and will stop for a permission prompt.

## See what is pinned, and clear one

```bash
node "${CLAUDE_PLUGIN_ROOT}/bin/pin.mjs" list --data-dir "${MUBIT_CC_DATA_DIR:-${CLAUDE_PLUGIN_DATA}}" --run <run_id> --json
node "${CLAUDE_PLUGIN_ROOT}/bin/pin.mjs" clear <slug> --data-dir "${MUBIT_CC_DATA_DIR:-${CLAUDE_PLUGIN_DATA}}" --run <run_id> --json
node "${CLAUDE_PLUGIN_ROOT}/bin/pin.mjs" clear --all --data-dir "${MUBIT_CC_DATA_DIR:-${CLAUDE_PLUGIN_DATA}}" --run <run_id> --json
```

`list` prints a slug beside each pin; `clear` takes that slug. `--all` clears only this
plugin's pins and never another client's state in the same run.

**Clearing is half the job.** A pin that outlives the task it was set for is worse than no pin:
it is spending tokens on every prompt to enforce a rule that has stopped being true. When the
work a pin was set for is finished, say so and offer to clear it.

## The limits, and why they are there

At most **five pins**, each at most **200 characters**, and at most **240 tokens** rendered.
The command refuses anything over them rather than silently truncating.

They are tight on purpose. Recalled memory is ranked against the prompt and degrades to a
one-line pointer once the model has already seen it; a pin does neither — it is unranked and
paid in full on every single prompt of the run. Six standing constraints is not a set of
constraints, it is a document, and a document belongs in `CLAUDE.md`, where it costs nothing
per prompt.

If a refusal comes back, do not work around it by shortening the user's words. Report the cap
and ask which existing pin to clear.

## Exit codes

| Exit | Meaning | What to tell the user |
| --- | --- | --- |
| `0` | Done. `--json` carries `run_id` and the full pin list. | Confirm what is now pinned. |
| `1` | Refused or failed. `detail` says which. | Pass the detail on. A cap was hit, the run could not be determined, or the instance did not answer. |

Two failures worth recognising by name:

- **`unconfigured`** — no endpoint is set. Run `/mubit-memory:auth` first.
- **`no_run`** — no hook has written a run marker yet, so the command cannot tell which run
  this session is. It resolves itself after one prompt; `--run <run_id>` names one explicitly,
  and `/mubit-memory:doctor` prints the current run id.
- **`ambiguous_run`** — two or more runs are live in the shared data directory and no `--run`
  was given, so the command refused rather than pin to the wrong session. `detail` lists the
  candidates. Re-run with the run id from the SessionStart block; do not pick one from the
  list by guessing which looks right.

## What a pin is not

- **It is not a permission boundary.** It is text put in front of the model, exactly like
  recalled memory. Use Claude Code's permission system for anything that has to hold.
- **It is not stored offline.** A pin that the instance did not accept is not written locally
  at all, because a pin that exists only on one machine is one the user believes is shared and
  is not.
- **It does reach subagents.** `SubagentStart` puts the parent run's pins above its own,
  smaller recalled block, under a budget of its own, so a fan-out is told the constraint too.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.