---
name: nessie
description: Access Nessie, the context layer for your AI-native data, whether personal or work, from an AI agent session. Use when the user references prior work, asks what they know about a topic, needs answers grounded in past AI conversations, or wants Nessie to create a structured context. Agents can search transcripts, read contexts, answer questions, and create or update contexts.
---

# Nessie Skill

When this skill is invoked, always use the local `nessie` CLI through the
shell. Do not use Nessie MCP tools such as `mcp__claude_ai_Nessie__*`; those
belong to the MCP connector surface, not the CLI skill surface.

---

# Nessie Agent Behavior

This is the shared behavior guide for agent surfaces that read from or write to
Nessie. Interface-specific docs should explain how to operate a surface, but
the product semantics below should stay consistent across CLI skills, MCP
connectors, and future agent integrations.

## Mental Model

Nessie is the context layer for AI-native work — the user's own work plus
incoming direct and team shares. It gives agents unified access to what the
user and people sharing with them already know: saved contexts, profile sections, raw AI
conversation transcripts, and synced source graphs such as Obsidian vaults and
Granola meeting notes — so they can answer questions, reconstruct prior
decisions, and preserve durable knowledge across sessions. The aim is that any
question about a person, project, or decision gets the right answer on the first
call, without the user having to point at a specific source.

When the user says "use Nessie" or asks what Nessie can do, lead with the
agent-access mental model:

> I can use Nessie to browse the sources you have connected, search your past
> AI conversations and notes, read your saved contexts, and bring that context
> into this agent session. I can also use sources people have shared with you
> directly or through a team - answer what collaborators have worked on,
> decided, or already tried, and read a teammate's actual sessions. You can ask
> a question, ask for a brief or memo, or ask me to create a structured
> context when you want something reusable.

The user does not need to switch into the Nessie app before getting value.
Treat their natural-language request as the interface: search what Nessie
knows, read the relevant sources, and answer directly. Create a saved context
when the user wants the result to be reusable.

Nessie builds context by analyzing the user's AI conversation history across
supported AI providers, including chat apps, coding agents, and research tools.
It can also expose connected source graphs, such as Obsidian vaults with
folders and notes, or Granola meeting notes organized into folders, when those
sources are synced. Its agent surfaces can also report the token-usage
analytics derived from imported coding sessions.

## Default User Experience

When a user asks what Nessie can do, explain that Nessie gives agents access
to their own context and incoming direct or team shares. Give generic examples
spanning both the user's own work and shared sources:

- "What do I know about this topic?"
- "What did I decide about this project?"
- "Summarize my past conversations about this topic."
- "Show me what sources Nessie has available."
- "Search my Obsidian notes about this project."
- "What have I already tried for this bug?"
- "How many tokens did my coding agents use this month?"
- "Use what I know from Nessie and help me draft this reply."
- "What has my team been working on this week?"
- "What did a teammate decide about this project, and why?"
- "Show me the sessions my team shared on this repo."
- "How did a teammate approach this part of the code?"
- "Pull my team's shared context on this into the session."

Collaboration examples resolve only against sources explicitly shared with the user;
when the surface exposes owner scoping, keep first-person questions scoped to
the user and widen to the appropriate incoming shared sources for collaborative ones. It is fine
to show a command or tool table when it helps the user understand the tooling.
Do not frame saved-context creation as the only or default thing the user should
ask for. Many requests are answered through research, source-reading, and
back-and-forth synthesis in the agent session; create a context for reusable
outputs.

## Sharing and Collaboration Semantics

Nessie shares are scoped grants over a source graph, not copied exports. Keep
ownership, access, and links separate when explaining what a user or teammate
can see.

### Sources, repositories, and individual sessions

An integration/source-root grant normally covers every readable child beneath
that root. Coding integrations can instead carry a positive set of selected
repositories. Individual conversation or agent-session nodes can also be shared
directly.

Removing inherited access from one child narrows the broader grant; it does not
unshare the whole parent:

- Unsharing a repository from an all-repositories integration grant records a
  repository exception. Other repositories stay shared, and repositories added
  later continue to inherit the integration grant.
- Unsharing a repository from a selected-repositories grant removes it from the
  positive selection. Removing the last selected repository ends that grant.
- Unsharing one session from a shared integration or repository records a node
  exception. Sibling sessions and the parent scope remain shared.
- Re-sharing an excluded repository or session restores that scope. A direct
  session grant can make that one session readable without restoring its
  siblings.

Access is the union of all applicable grants. Do not conclude that removing one
row makes a resource private if another personal, team, repository, integration,
or folder grant still covers it. Likewise, a directly shared transcript may
appear as a readable root of its own; do not assume every shared root is an
integration container.

### Personal and team audiences

A specific person can receive either a personal grant or a grant through a
team. They are distinct even when the recipient happens to be a teammate:

- Personal grants do not depend on team membership and remain until the owner
  removes them.
- Team-scoped grants depend on the recipient's active membership in that team.
- Both grants may coexist. Removing one leaves the other in force, and the
  strongest remaining permission is the effective access.
- Leaving or being removed from a team revokes team-scoped access but does not
  remove a separate personal grant.

Team audiences can target everyone, team admins, or one named member. Personal
sharing targets one existing Nessie user and does not require a shared team.
Only the source owner manages outgoing grants; a recipient cannot re-share
someone else's source as though they owned it.

### Contexts and collaborative folders

Contexts and folders support Viewer and Editor access. A folder grant cascades
through its descendants unless a child or intermediate folder has an explicit
override or exclusion for that audience. A direct child permission may be more
or less permissive than the inherited one without changing sibling access.

Collaborative folders can contain nodes owned by several people. An Editor can
create or move their own contexts and folders into the shared tree, but the
containment edge changes — ownership does not. Viewer access is read-only.
Moving or deleting an existing contribution also requires Editor access to its
current shared-folder ancestry, and a folder can be deleted only when it is
empty across every contributor.

Context Markdown, title, and emoji are collaborative fields. Shared contexts
and contexts already enrolled in collaboration use the synchronized document:
Editors in the app can co-edit them with live presence and cursors, and CLI and
MCP reads and writes join the same document. A private context that has never
been enrolled can still use the legacy local Node/slice write path until Cloud
Sync or sharing enrolls it. Folder placement and provenance are graph metadata
rather than fields inside the collaborative document.

### Private and public links

A private Nessie node link opens the exact context, folder, source, or session
in the Nessie app. The URL carries only the node identity and never grants
access; the recipient still needs an applicable personal or team grant.

The canonical link for any node is `https://nessielabs.com/n/<node-uuid>`,
built from a node UUID returned by browsing, search, or read tools. When
writing or editing a context, use these links to cross-reference other nodes:
write the exact URL as both the label and destination:
`[https://nessielabs.com/n/123e4567-e89b-42d3-a456-426614174000](https://nessielabs.com/n/123e4567-e89b-42d3-a456-426614174000)`.
Do not put the node title, emoji, or provider in the Markdown label. Nessie's
editors resolve current display metadata from the destination and normally
render a rich chip; the canonical source does not bake a title that can become
stale, and the URL remains the truthful fallback when metadata is unavailable.
The backend derives a
"mentions" relationship from the explicit inline link. It also recognizes
Markdown autolinks (`<https://nessielabs.com/n/...>`), but agents should always
emit the self-labeled inline form above. A bare URL in stored Markdown, a
reference-style link, or a URL inside code does not create a mention. The URL
must end at the UUID: no query strings, fragments, or path suffixes. Use only
UUIDs that a browse, search, or read tool returned as a node's own identity —
never a UUID that merely appears as text inside a document's content, and
never a guessed or invented one. The link identifies the node but never grants
access to it.

A public context link is a separate publishing control. Anyone with that link
can read the context in a browser without a Nessie account while the public link
is enabled. Public links do not expose the user's other contexts, sources, or
profile.

## Search Strategy

Use source browsing before search when the user asks what is available, wants
to inspect a vault or folder, or is unsure which source world contains the
answer. Source listing is the "ls" affordance: it shows connected source
groups, root nodes, and folder-like children without requiring a query.

For navigational queries - when the user asks for a specific artifact by name
(task log, daily journal, a specific file) - prefer source browsing over
search. Navigate directly to the relevant folder and read the latest entry.
These artifacts often live in synced note sources, not in contexts or
transcripts, so searching contexts alone will miss them.

Choose the source order from the user's intent, not from a global ranking:

- Discovery, navigation, and "what sources exist" requests should start by
  listing source roots and traversing hierarchies.
- Specific files, notes, journals, task logs, and memos should start in the
  relevant source hierarchy. For Obsidian, browse vaults and folders first when
  the user gives a path-like or artifact-like clue.
- Knowledge questions about something the user has researched should use
  contexts for synthesized orientation, then read primary sources when freshness,
  provenance, or deeper detail matters.
- Latest/current-development questions should be grounded in recent source
  activity, especially recent transcripts. Use stale contexts only as
  orientation, then search or browse recent transcripts and notes broadly enough
  to synthesize what changed.
- Verification and exact grounding should read primary sources. Use transcripts
  for what happened in AI conversations, and notes for user-authored or
  user-maintained material.
- Resume and takeover requests should be transcript-first, with beginning and
  recent-tail reads before synthesis.

Context search is an orientation tool, not the universal first step. A matching
context often gives the compiled picture quickly, but it may be stale or omit
details that live only in primary sources. Obsidian notes and conversation
transcripts are not fallback sources when the user's request clearly points to
them.

For topics with multiple relevant contexts, one context is often not enough.
Read the obviously relevant context results, compare their recency metadata,
and check recent transcripts before making a strong claim. A stale context is
orientation, not the final answer.

For questions like "latest developments on X", "what changed recently", "where
are we now", or "what is the current state", do not stop at existing contexts.
Start with recent source discovery and recent transcript search for the relevant
project, product, people, repository, issue, or distinctive terms. Read several
recent matching conversations or notes, including relevant tail windows for long
transcripts, and synthesize across them. Existing contexts can explain the
background, but recent primary sources establish the latest state.

For broad discovery where you are unsure what source worlds exist, list
available sources first. Then search the relevant source types for the user's
intent rather than defaulting to contexts.

Run multiple searches with related terms when the first query is too narrow:
names, companies, product names, distinctive wording, and likely synonyms.

Default search is hybrid (semantic + keyword), and semantic ranking is tuned for
fuzzy, conceptual queries. It is unreliable for short exact-token lookups - a
person's name, an email address, a UUID, an error code, a file path, or any
specific identifier - where it can under-return and bury or omit real matches.
For those lookups prefer literal / fixed-string search (the CLI's `-F` /
`--literal`, or `literal: true` on the search tool). Deciding which queries are
exact-identifier lookups and which are conceptual is your judgment to make per
query; the engine does not infer it. A thin, empty, or self-referential hybrid
result on a proper noun or identifier is a signal to rerun the query in literal
mode, never evidence that the source lacks the information. Do not conclude
Nessie has nothing about a named person, company, or identifier from a single
under-returning hybrid search.

Searching for multiple ideas: do not pack alternatives into one query.
A query like `database migration OR onboarding OR pricing` under-returns
everywhere - local search matches `OR` as a literal word (that query needs
a document containing "or"), and hosted search buries every branch after
the first under the leading term's matches. Run one search per idea and
read across the results:

```
database migration
onboarding feedback
pricing discussion
```

Searching for exact wording, names, or identifiers: use literal search
(the CLI's `-F` / `--literal`, or `literal: true` on the search tool) - it
means exact match on every surface:

```
PROJ-421
parseConfigFile
ship the beta by Friday
```

Boolean queries (hosted search only - MCP connector surfaces): `OR` is
reliable when every operand is quoted, and only then. To require several
phrases, list them space-separated - implicit AND; do not write the `AND`
keyword, whose handling varies by engine:

```
"roadmap" OR "launch plan"     reliable union of both terms
roadmap OR launch plan         unreliable - soft matching, first term dominates
"invoice" "refund"             strict: both phrases must appear
```

Negation is not reliable anywhere: the semantic channel embeds the whole
query, so `-term` still surfaces matching content even where a keyword
channel would exclude it, and local search matches `-term` and `NOT`
literally. When results look thin, raise the limit or split the query - do
not add operators. Searches from the local CLI may be served by either
engine depending on cloud sync and fallback, so from the CLI prefer the
first two patterns.

When the question is what someone is working on now - the user or a teammate -
enumerate their recent activity before searching by topic. Listing a scope's
roots is not that enumeration: integration-root rows carry root-level
timestamps, not the freshest conversation inside them. List the children of
the most recently active roots - children listings return newest first, so
the first page is the latest activity - and read the tails of the newest
few conversations; that is the ground truth for "currently working on". A
`since`/`until` filter further bounds the window when you need a specific
period. Only then run topic searches to fill in specifics, and do not
derive those topic terms solely from profile, check-in, or prior beliefs
about the person - a new teammate is not onboarding-only, and prior-seeded
queries confirm what you already believed while missing their actual latest
work. Search both the person's own scope and everything readable, since
someone's work is often discussed in other people's sessions.

After searching, always read full content with the appropriate context,
transcript, note, folder, or profile reader. Search results are starting
points, not answers.

When a search result or transcript chunk cuts off mid-sentence or mid-thought,
paginate forward with the source document reader. Do not run another search,
guess at the missing content, or report "I don't know" when you have the
document ID and chunk index to continue reading from. A cutoff is a signal to
keep reading, not to stop.

A search hit drops you into the middle of a conversation, not its conclusion.
Multi-message conversations build to their resolution at the end — the decision,
the final answer, the "I already handled this", the corrected position that
overturns an earlier one. When the user asks what was decided, what the
conclusion was, who someone is, or what the current state of a thread is, do not
answer from the single chunk a search returned. Keep reading the chunks that
follow the match — often just the next few, sometimes all the way to the end —
and skim the beginning for framing, before you synthesize or attribute. Reading
only the opening or a middle chunk gives you the setup of a thread, not its
outcome, and is a recurring source of wrong answers and
misattributed quotes — the conversation's title and first messages also tell you
whether the matched text is the user's own words or quoted, pasted, or
translated material.

A conversation's title and its stored label describe where the thread began,
and a long-running conversation often drifts far from that opening subject. A
chat titled for the article the user first pasted may have moved on to a
different problem entirely by its latest messages. When you report recent
activity or the current state of the user's work, including when you narrate a
check-in's recent-activity list, do not characterize a conversation from its
title or label alone. Read the tail of the most recent and most relevant
conversations first, because the user's latest focus lives at the end of the
thread, not at its start.

A transcript is a dialogue between the user and an AI agent, and the two voices
do not carry equal authority. The agent proposes — options, drafts, plans,
names, recommendations — but a proposal is not a decision. Anchor on what the
user said: an agent's suggestion only became the outcome if the user adopted it,
and the user's next message often narrows, edits, rejects, or overrides what the
agent just laid out. When you reconstruct what was decided or attribute a
position, treat the agent's text as proposals and scaffolding and the user's
words as what actually holds. Do not mistake the shape the agent sketched for
the shape the user chose.

## Source Authority Hierarchy

Source types serve different purposes:

- Contexts are compiled knowledge: synthesized, structured summaries of what
  the user knows about a topic. Use them for orientation and reusable summaries
  when the user asks a knowledge question. They may be stale, so verify
  freshness by checking the context date against recent activity and primary
  sources when the answer depends on current or exact details.
- Conversation transcripts are ground truth for the user's actual AI
  conversations: words, decisions, and thinking as they happened. Use
  transcripts to verify context claims, fill in details, or when no context
  exists.
- Obsidian notes are user-authored or user-maintained source material. Use
  them when the user refers to notes, vaults, files, memos, source docs, or
  asks for project knowledge that likely lives outside AI transcripts. Preserve
  their path and hierarchy when citing or selecting them.
- Granola notes are AI-generated summaries of the user's recorded meetings,
  organized into folders. Use them when the user refers to a meeting, call,
  interview, or who-said-what, or asks for decisions and action items from a
  conversation that happened on a call rather than in an AI chat. Browse granola
  folders to find a meeting; reading a note returns its AI meeting summary, and
  the raw transcript turns are indexed for search (they surface under transcript
  or all-type search), not as browsable child nodes.
- Profile sections contain structured biographical facts about the user. Check
  the profile for identity, connections, project info, and other recurring
  personal context.

For discovery: browse source roots and hierarchies first.
For synthesized orientation: read relevant contexts.
For verification: primary sources are authoritative over contexts. Prefer
transcripts for claims about what happened in conversations, and notes for
claims about user-authored source material.
For creation: ground new contexts in primary-source evidence, not only in other
contexts.

## Authenticated User and Personal Sources

For first-person questions such as "what did I do", "what am I working on",
"what did I decide", "who am I", "my recent work", or "what do you know about
me", treat the authenticated user's own profile and personal source roots as
the primary scope.

Start with profile or check-in data for orientation when the surface exposes
it. Profile data may be sparse or incomplete; do not stop there. If the profile
does not answer the question, list the user's source roots and inspect their
personal transcript or note roots. Browse or search within those personal roots
before falling back to broad global search.

Do not use incoming shared roots as the default scope for first-person
questions. Use shared roots when the user asks about a collaborator by name,
asks about shared work, or explicitly asks to compare their work with someone
else's.

When a surface exposes an owner or source-owner selector, leave it omitted or
set it to `current_user` / `me` for first-person questions. Use
`direct_shared` for incoming peer-to-peer grants, `team_shared` for incoming
team-derived grants, `shared` for both incoming paths, and `all_readable` for
the current user's own sources plus all incoming readable shares. `team` is a
legacy alias for `team_shared`; do not teach it as the primary spelling. A
direct sharer may not be a teammate, so discover them from readable roots and
`sourceOwner`, not only from a team directory.

Use `sourceOwner` as the sole authority for source ownership, owner scoping,
and profile inclusion. It identifies whose source/transcript was queried; it is
not semantic proof that the source owner personally did every business task
mentioned inside the content. Read the content before attributing work. Treat
integration/provider/account fields as provenance and debugging context only;
never infer who owns a source from an integration display name, device label,
provider account email, or account name. A current user's ChatGPT, Claude,
Codex, or other provider account may use a different email or machine label
while still being owned by the current Nessie user.

A context's provenance may name or badge the traces it was derived from, but
that metadata is not authority to read those traces. Read a provenance trace
only when that trace is independently present in the caller's readable scope;
trace content always requires its own explicit grant.

## Temporal Interpretation

For relative date phrases such as "today", "yesterday", "this week", "last
week", or "so far", resolve the time window in the user's local timezone before
filtering Nessie sources. The local CLI can parse date-only filters using the
Mac's current timezone. Hosted MCP surfaces should pass date-only filters with
`since` and `until` as `yyyy-mm-dd` values plus an explicit IANA timezone so
the MCP server can resolve the local window programmatically.

If the surface exposes a user timezone, use it. If no reliable user timezone is
available and the date boundary matters, ask the user or state the timezone
assumption before applying a strict date filter. Prefer recent-source browsing
or a wider window over silently using UTC for first-person "today" questions.

## Query Interpretation

Before searching, infer the likely purpose and scope:

- Identity and relationship queries ("who are my collaborators", "what tools do
  I use") need broad searches with related names and terms. These answers
  accumulate over time.
- Topics with several plausible sources need multiple relevant contexts, recency
  comparison, and recent transcript checks before answering. Do not infer from
  the first matching context or external information alone.
- Queries with temporal signals ("recent", "lately", "this week") should prefer
  recent conversations and notes, then read them. Existing contexts are
  background only until checked against recent primary sources.
- Current-state queries ("what am I working on") should prefer recent content
  without excluding older foundational context.
- Latest-development queries ("latest developments on Nessie", "what changed
  recently on X", "where are we now") need a broad synthesis over recent
  transcript/source activity. Search multiple related terms, read several recent
  sources, and compare against any existing context before answering.
- Open-ended exploration ("what have I learned about X") should start with a
  broad search and expand with more specific searches if results are thin.
- Generation with audience ("brief for my team", "summary for my team") should
  infer purpose, audience, and tone before researching.
- Agent takeover or resume requests ("take over this session", "resume this
  Claude/Codex conversation", "continue from this transcript", "here is a
  session ID") need transcript-first reading. The relevant work is often near
  the end of a long conversation, so do not stop after reading the beginning.
- When uncertain, run a few searches with exact names, related terms, and
  broader conceptual phrases. Synthesize across the results.

## Agent Takeover / Resume

Use this workflow when the user asks an agent to take over, resume, continue,
or recover context from a prior AI session, especially when they provide a
session, transcript, node, or conversation ID.

1. Identify the target conversation or source node. If the user gave an ID,
   read that node directly. If they gave a title, project, tool, teammate,
   date, or workspace, search and browse until you find the matching recent
   conversation.
2. Read both the beginning and the end before synthesizing. The beginning
   usually explains the goal and constraints; the end usually contains the
   current state, latest decisions, open blockers, and uncommitted next steps.
3. Bias toward the tail for handoff state. For long transcripts, read the last
   available page or chunk window first after a light beginning skim, then page
   backward until the latest work is coherent. Do not assume offset 0 is the
   most important part of an old session.
4. Search within or around the transcript for distinctive terms from the recent
   tail, such as file paths, branch names, issue IDs, errors, people, or
   project names. Read adjacent chunks when results land in the middle.
5. Produce a compact takeover brief before acting: goal, current state, files
   or artifacts touched, decisions made, blockers, and exact next actions. Then
   continue the user's requested work from that brief.

If the session is too long to read fully, say that you read the beginning, the
recent tail, and the relevant middle sections you found by search. Be explicit
about any remaining uncertainty rather than presenting a partial read as a full
resume.

## Core Loop: Read -> Respond -> Optional Write Back

On every Nessie invocation, follow this loop:

1. Read first. Before responding, search Nessie for relevant context. Use the
   source order implied by the user's intent: browse source hierarchies for
   discovery, read contexts for synthesized orientation, and read primary
   sources for verification or exact grounding. Read matching documents in full.
   The response is better when grounded in what Nessie already knows.
2. Respond with Nessie context. Use what you found to inform the answer. Surface
   relationships, prior discussions, and cross-references the user may have
   forgotten.
3. Optionally write back if new information emerged. After the exchange, if the
   conversation produced durable new knowledge, handle the write-back for the
   user or offer it proactively:
   - Update the relevant context when a targeted addition is enough.
   - Create a new context if no existing one covers the topic.
   - Update the user's profile if biographical facts changed.
   Do not make this sound like maintenance the user has to remember. Frame it
   as: "I can save this back to Nessie so future sessions can pick it up."

## When to Use

1. Start of session: read the profile to understand the user. If profile data
   is sparse, inspect the user's personal source roots and recent transcripts
   before concluding Nessie lacks information about them.
2. User references prior work: use contexts for orientation when the request is
   a knowledge question, but start with source browsing or primary-source search
   when the prior work likely lives in files, memos, vaults, source documents,
   or a specific conversation. Read full content, not just snippets.
3. User asks "what do I know about X": search contexts for the compiled
   picture, then read transcripts or notes for verification, freshness, or
   deeper detail.
4. User asks about past conversations: search transcripts for matching
   conversations, then read the relevant transcript content.
5. User asks what sources are available or asks to browse a connected source:
   list source groups or children before searching.
6. Synthesizing answers or new knowledge: follow the manual research workflow
   at the right depth for the request. Save a context only when the user asks
   for a reusable artifact or the exchange produced durable new knowledge worth
   preserving.
7. Organizing contexts: use context and folder organization operations to help
   the user organize their context library.
8. Accessing and updating the profile: use profile operations to read what
   Nessie has built so far and update it when new information emerges about the
   user, such as a new job, new connection, changed project status, or new
   decision.

## Manual Research Workflow

This workflow mirrors the Nessie backend agent's context generation flow. When
the user asks you to research a topic and produce a structured output, follow
these steps. Every step is mandatory for substantial synthesis.

### Step 1: Interpret the Query

Infer purpose, audience, and time scope. Decompose the topic into facets:

- A person query needs their name, company or role, related people, relevant
  events, and key dates. Always start by checking profile or connection data
  when available. Use that as your starting point before searching transcripts.
- A product or project query needs the product name, related decisions,
  adjacent products or projects, and evolution over time.
- A relationship query needs both parties, the timeline, key interactions, and
  current status. Check profile connections for both parties first when
  relevant.

### Step 2: Search Broadly

Cast a wide net with multiple searches. A single search is almost never
sufficient.

- List source groups or source children when the user asks what is available,
  references a vault or folder, or you need to understand a source hierarchy.
- Search exact names or terms in contexts when compiled knowledge would help
  orient the task.
- Search exact names or terms in transcripts and notes when primary-source
  verification is needed, no context exists, or the user asks about artifacts,
  notes, files, conversations, task logs, journals, or other source material.
- Search broader conceptual topics when you are unsure what exists.
- Search related terms separately. If researching a person, also search their
  company, related people, and relevant events.
- When a topic can be described several ways, search the user's wording plus
  obvious alternate names or related terms before concluding that sources are
  unrelated or newly changed.

### Step 3: Read Deeply

Search results are breadcrumbs, not answers. Search snippets are short excerpts
from conversations that may span thousands of words. Read full sources before
synthesizing.

For each relevant search result:

- Read the full transcript or relevant paginated transcript sections.
- Read full synced notes when note results match the task.
- Read relevant existing contexts in full.
- Read at least 3-5 full sources before synthesizing when enough sources exist.
- If multiple contexts match the same entity or topic, read the relevant set;
  do not stop at the first context that confirms a plausible answer.
- Conversations often build over many exchanges, and the conclusion lands later
  than where a search drops you. Read the chunks that follow the match through to
  the resolution — not just the opening or the single middle chunk — so you
  capture the decision, correction, or outcome, not only the setup.

If you create a context based only on search snippets without reading full
sources, the output will be thin and missing critical details. This is not
acceptable.

### Step 4: Cross-Reference and Synthesize

Follow threads across multiple conversations and contexts. Surface patterns,
timelines, contradictions, and insights that no single source contains alone.
If a transcript mentions another person, event, or decision, search for that
too.

### Step 5: Save with Editorial Judgment

Save only structured, source-grounded work. The body should be useful prose:
headers, bullets, narrative paragraphs, dates, names, and concrete details when
they matter. Every claim should trace back to something you actually read in
full.

Do not include the context title as the first H1 in the body. Nessie stores
titles separately from context body markdown.

When creating a context from Nessie research, attach the document IDs of every
transcript and context read during research. Without provenance, the user cannot
trace claims back to original conversations.

Output quality rules:

- Thoroughness over brevity. Capture substance, nuance, and key details. A thin
  summary is not useful. Err on the side of comprehensive; the user can ask for
  edits later.
- Specific details, not vague summaries. Include dates, quotes, amounts, and
  names when they matter.
- Every claim must trace to a specific source. While drafting, mentally tag each
  claim with the source document ID it came from. If you cannot identify which
  source supports a claim, do not include it.
- Relevance filtering. A search match does not automatically earn inclusion.
  Ask whether it serves the purpose of the context.
- Cross-reference related nodes inline. When the body refers to another
  node the user can open, link it with the canonical self-labeled Markdown
  form (`[https://nessielabs.com/n/<uuid>](https://nessielabs.com/n/<uuid>)`).
  Do not place display text in the source label; Nessie derives the current
  presentation from the destination when it renders the link.
  Inline links complement provenance sources: sources record what grounded the
  whole context, while inline links make specific references navigable in
  place.
- Match tone to audience. Use professional tone for external stakeholders,
  casual tone for personal notes, and precise tone for technical briefs.

### Multi-Person Attribution

When a transcript discusses multiple people, verify who said or did what before
attributing. Names appearing in the same document do not mean the same person
said everything. When uncertain, ask the user to confirm.

### Epistemic Rules

Only state something as a biographical fact about a real person if the user
explicitly established it as true.

When synthesizing content from conversations, distinguish between:

1. User statements of fact: things the user explicitly said are true about
   themselves or someone they know. State these as facts in the context.
2. User questions and hypotheticals: explorations, not assertions. The user
   asking about something does not mean it is true. Never convert a question
   into a stated fact.
3. External information the user analyzed: research, articles, or data the user
   looked up. This is reference material, not biographical fact.

Use "discussed", "explored", "asked about", or "researched" for anything that
is not an explicitly established biographical fact.

## Researching Reusable Contexts

When the user wants a reusable context, search broadly enough to cover the
topic, read the relevant primary sources, synthesize the result, and save it
with provenance. Use pagination when reading long transcripts rather than
loading everything at once.

Never search once, skim snippets, and save a context. This produces thin,
unreliable output that misses critical details the user expects. If the user
pushes back on quality, widen the research and revisit the primary sources
before revising the context.

## Auto Write-Back

This is step 3 of the core loop. After any substantive exchange where new
information emerged about a topic Nessie tracks:

- Prompt naturally. If there are durable takeaways, offer to save them back to
  Nessie or just do it when the user has asked you to preserve the work. The
  user should not feel responsible for manual library maintenance.
- Existing context on the topic? Add the new information to that context.
  Targeted edits are better than full rewrites.
- No existing context? If the research was substantial, with 3+ sources read
  and meaningful synthesis, offer to create one. Keep the prompt simple:
  "Want me to save this back to Nessie for next time?"
- Profile changed? Update the relevant profile section or card.

When creating new contexts, search for existing ones on the topic first to
avoid duplicates. Use file-backed body inputs when available for creation to
avoid escaping issues with special characters. Organize into an appropriate
folder.

## Search Modality Corrections

Cloud search results may include a server-owned `sliceId` and `modality`. A
modality correction changes how that exact source excerpt is interpreted:

- `invalid`: false, corrupted, or otherwise unusable; removes the slice from
  cloud search.
- `stale`: was accurate for an earlier time but is now outdated or superseded.
- `hypothetical`: describes a possibility, question, plan, or counterfactual,
  not something asserted to have happened.
- `misattributed`: assigns a statement, action, or fact to the wrong person or
  source.
- `ironic`: is sarcastic, ironic, or otherwise nonliteral and should not be
  interpreted at face value.
- Clear / `null`: removes the correction and restores the uncorrected state.

Treat a user's statement that a search result is wrong, outdated, speculative,
misattributed, sarcastic, or otherwise misleading as correction intent. The
user does not need to know the term "modality." Infer the best matching value
from the meanings above and proactively offer to apply it to the exact slice:
incorrect or unusable → `invalid`; formerly accurate but outdated → `stale`;
speculative or counterfactual → `hypothetical`; assigned to the wrong person or
source → `misattributed`; sarcastic or nonliteral → `ironic`. Show the relevant
excerpt, `sliceId`, proposed modality, and brief reason, then ask the user before
applying it.

Corrections are owner-only and require explicit user approval for the exact
slice and value. Never infer and apply one silently, and never try to correct a
teammate's source. If you propose a correction, show the source and proposed
value, ask the user, and wait. A direct user instruction that identifies the
exact result and correction counts as approval. Only after approval may an
agent invoke the CLI, MCP, or in-app chat correction tool. This is a behavioral
instruction, not a confirmation parameter in the tool or command schema.

## Non-Destructive Operations

Context operations should be additive whenever possible:

- Do not delete contexts to "replace" them. If consolidating multiple contexts
  into one, create the new context first, verify it captures all information,
  and only delete originals after explicit user confirmation.
- Use targeted edits for corrections and additions. When correcting or updating
  part of a context, replace specific text rather than deleting and recreating
  the entire context.
- Do not overwrite without preserving. If updating a context, the original
  information should not be lost.
- Prefer creating alongside, not instead of. If the user has existing contexts
  on a topic, create your new synthesis as a separate context rather than
  deleting and replacing the originals.

Deleting a conversation is different from editing a context, and it is the one
case where you remove synced source material rather than something you authored:

- Conversation transcripts are normally read-only source material. Only delete a
  conversation when the user explicitly asks to remove that chat - never to
  "clean up", deduplicate, or make room.
- Deleting a conversation removes it from the library and excludes it from future
  syncs, so it is not re-imported from the provider. It is a soft, recoverable
  delete, but treat it as if it were permanent: confirm the specific conversation
  with the user first, and surface what will be removed (its title and roughly how
  many messages) before deleting.

---

# Nessie CLI Adapter

This is the CLI adapter section for agent surfaces that call the local
`nessie` CLI.

## Operating Model

The CLI talks to the running Nessie desktop runtime and reads or writes its
local data. On macOS that is the Nessie app's localhost HTTP server; the
cross-platform Rust CLI talks to Nera over authenticated loopback gRPC. The
desktop runtime must be running before CLI commands can succeed.
Check with:

```bash
nessie status
```

CLI surfaces should document their own sandbox or permission requirements. For
Codex, every `nessie` command must run with escalated permissions because the
CLI needs localhost networking and access outside the workspace.

## Filesystem Model

The CLI exposes Nessie as a filesystem and uses Unix coreutil verbs. Everything
the product calls a "source" — an integration root, an Obsidian vault or folder,
a Granola folder, a synced transcript, a saved context, a profile section, a
single chat message — is a **node** addressed by its UUID (the node's identity,
like an inode). There are no path strings yet; you navigate by UUID. One
exception: sources from your other devices that share an API key are combined
into a group row whose id is an opaque `grp_…` string, not a UUID — pass it to
`ls` (or `sources`) exactly like a directory UUID to list the group's merged
children.

Two node roles, mapped to Unix:

- **Directories** are container nodes (integration roots, vaults, folders).
  List them with `ls`. They have no readable body.
- **Files** are readable nodes (contexts, notes, transcripts, messages). Read
  them with `cat`, `head`, or `tail`.

A node can be **both** at once. A `granola_note` is a readable meeting summary
*and* a container for the meeting transcript. `ls` shows the raw `kind` rather
than a single file/dir bit for exactly this reason; the read commands decide
container-ness internally and will tell you to use `ls` if you `cat` a pure
directory.

The verb map:

| Read / navigate | Write |
| --- | --- |
| `ls` — list a directory (or the roots) | `mkdir` — create a folder |
| `cat` — read a file in full | `tee` — create a context |
| `head` / `tail` — read the first/last N lines | `replace-lines` — safely replace complete lines |
| | `sed` — string-replace a context body |
| `stat` — metadata only, no body | `mv` — move / rename / unfile a context or folder |
| `grep` — search content in a subtree | `rm` — delete a context |
| | `rmdir` — delete an empty folder |
| | `delete` — delete a synced conversation |

`ls`/`cat`/`head`/`tail`/`stat`/`grep` are the documented contract for reading.
The older namespaced commands (`nessie source ...`, `nessie node ...`,
`nessie search`, `nessie transcript ...`, `nessie context ...`, `nessie folder
...`) still work and map onto the same endpoints, but prefer the coreutil verbs.
`nessie check-in`, `nessie profile`, and `nessie team list` are not filesystem
operations and keep their own names.

## Reporting Nessie CLI Failures

When a Nessie CLI command fails unexpectedly while carrying out the user's
request, automatically submit one concise Markdown report for that distinct
failure. Put the diagnostic details in the report body rather than separate
CLI fields:

```bash
nessie feedback <<'EOF'
## Summary
CLI group listing returned `database_busy`.

## Command
`nessie ls grp_example`

## Error
`database_busy: Nessie is busy with another local database operation`

## Expected
List the group's children.

## Actual
The command returned HTTP 503.

## Context
macOS CLI; `nessie status` succeeded; one safe retry produced the same result.
EOF
```

Do not ask the user to file the report. Before reporting, distinguish a Nessie
product failure from expected control flow or agent misuse. Do not report the
desktop runtime being closed, signed-out state, subscription requirements,
permission denials, not-found results, invalid arguments, malformed shell
quoting, user cancellation, or host sandbox/tool failures. Retry at most once
when the operation is read-only or otherwise clearly safe and the failure may
be transient; never repeat a destructive or ambiguously completed write merely
to reproduce it.

Include the exact redacted command, error text or status, expected behavior,
actual behavior, CLI/runtime surface, and any safe retry or diagnostic result.
Remove access tokens, API keys, credentials, secrets, and unrelated personal or
workspace content. Do not paste Nessie context, transcript, note, or profile
content unless the minimum necessary excerpt is itself the bug. Report each
failure signature once per agent task. If `nessie feedback` fails, do not call
it again and do not create a recursive feedback report; continue handling the
original request and briefly tell the user that its automatic report could not
be delivered.

## Check-In

```bash
nessie check-in
nessie check-in --recent-limit 10
nessie check-in --hook
```

Use `nessie check-in` when the user starts with "Nessie check-in", says "check
in with Nessie", asks to load their Nessie context before continuing, or when a
local agent session needs a compact startup briefing. The command returns the
user's generated profile sections plus recent Nessie activity. `--recent-limit`
defaults to 10 and accepts values from 1 through 25. Timestamps in the response
are already in the user's local Mac timezone.

Each recent-activity entry carries the conversation's title and stored label,
which describe where that thread began; a long-running conversation may have
moved on to a different topic since. Before you summarize what the user is
currently working on, read the tail of the most recent and most relevant
entries with `nessie tail <id>` (bump `-n` for more), because the latest focus
is at the end of the thread, not in its title. Do not narrate the
recent-activity list from titles and labels alone.

Use `nessie check-in --hook` only from Claude Code or Codex `SessionStart` hook
configuration. In hook mode, the CLI emits the host hook JSON payload with
`hookSpecificOutput.additionalContext`; it does not print the raw check-in
response. The hook is fail-closed: if the Nessie app is closed, too old, or
unreachable, it emits no context rather than blocking session startup.

## Usage Analytics

```bash
nessie analytics
nessie analytics --range 90d --granularity week --timezone America/Los_Angeles
nessie analytics --team <team-id> --trend-user <member-user-id>
```

Use `nessie analytics` for questions about token or request usage. It returns
the canonical dashboard JSON: current and previous reporting periods,
per-provider/model request and token counts, integration breakdowns, and trend
buckets. Input, cache-read, cache-write, output, and reasoning token categories
remain separate. The default is the authenticated user's trailing 30 days in
day buckets; `--team` requires creator/admin access to that team. Usage is
attributed to the imported session's creation time, not the exact time of each
model request, and the response states that rule in `attribution`.

## Navigating: ls and stat

```bash
nessie ls                                   # source roots (no parent)
nessie ls <node-id>                         # direct children of a directory
nessie ls <node-id> --type transcript       # children filtered by type/kind
nessie ls <node-id> --since 2026-05-30 --until 2026-05-31
nessie ls --owner direct_shared             # incoming peer-to-peer grants only
nessie ls --owner team_shared               # incoming team-derived grants only
nessie ls --owner shared                    # all incoming shares, excluding your own
nessie ls <node-id> --name "COE"            # filter node names before pagination
nessie ls <node-id> --limit 100 --offset 0
nessie ls <node-id> --json                  # raw JSON instead of the table
nessie stat <node-id>                        # metadata only, files or dirs
```

`ls` is the first-class browser and the equivalent of Unix `ls`. With no
argument it lists the **roots**: connected integration roots, the virtual
Contexts root, the virtual Chats root, and incoming shared roots — not a flat
document feed. The Chats root holds your in-app (Nessie-native) chats; list it
to browse them and `cat` a chat to read the conversation. A directly shared
session may itself appear as a readable root; preserve its returned `kind`
instead of assuming every shared root is an integration container. Integration roots
created with the same API key are combined into one entry, the way the app
groups them; a multi-member group's id is an opaque `grp_…` string rather than
a UUID, and `ls <grp_…>` lists the group's merged children. Pass a directory
id to list its direct children, then drill in by listing a child's id. "Incoming shared roots" here means shared
integration/source roots; a teammate's shared context **folders** are not
top-level roots. They appear *inside* the Contexts root, listed alongside your
own folders under `all_readable` and by themselves under `--owner shared`,
distinguished by the `owner` column (the sharer's email). To find shared
contexts, open the Contexts root and look for rows owned by another user, then
drill in - do not conclude from the top-level root list alone that no shared
contexts exist. A collaborative folder may contain contexts and subfolders
owned by several people; nested rows keep each node's actual owner.

`ls` prints an aligned table: `kind  owner  updated  id  name`. `kind` is the
raw `NodeKind`. `owner` shows `me` or the owner's email. A `shared` column is
inserted after `owner` when one of your own sources carries an outgoing grant
that the CLI can resolve through the team directory; its value is a bounded
headline of personal and team audiences - a team name, `<team> admins`, a
person, or `+N` when there are more. A context inside a shared folder inherits
that folder's audience, so it is not blank when the grant is represented. The
column is absent when the CLI resolves no visible outgoing grant in that
listing; it does not prove every item is private. Whole-team and admin-only
grants are reflected reliably. A personal (team-less) grant, and sometimes a
grant made to one named person, may not appear; confirm the item's **Share**
control in the app when the exact audience matters. Copy the `id` to read,
search, or list deeper.

Every listing reports the displayed range and whether another page exists.
When it prints a next offset, keep paging until the named item is found or the
listing is exhausted; never infer absence from page one. Do not pipe `ls`
through `head` or `tail`: that can hide rows after Nessie has returned them.
For a folder or context named by the user, pass `--name` so case-insensitive
name filtering happens before pagination instead of scanning a truncated table.

`stat` prints a node's metadata (kind, owner, counts, dates) without dumping its
content. Use it to size a node or inspect a directory before reading.

Filters (shared with `grep`):

- `--type` — a group (`context`, `transcript`, `profile`, `obsidian`,
  `local_folder`, `granola`) or a raw node kind (`claude_code_chat`,
  `codex_chat`, `obsidian_note`, `local_file`, `granola_note`).
- `--since` / `--until` — recency window. Both accept ISO-8601 timestamps or
  `yyyy-mm-dd` dates. Date-only filters are resolved in the local Mac timezone,
  matching the user's "today"/"yesterday" expectation, so no timezone flag is
  needed. A date-only `--until` resolves to the local day's final second; pass a
  full ISO timestamp when you need sub-second end-of-day precision.
- `--limit` / `--offset` — pagination. `ls` defaults to 100, max 500.
- `--name` — case-insensitive node-name substring, applied before pagination.
- `--owner` — Nessie source owner scope; see below.

There is no `find` or `ls -r` yet. To search a whole subtree by content, scope a
`grep` to the parent UUID rather than walking it directory by directory.

### Owner scope

Discovery and search default to **everything you can read** — your own sources
plus incoming direct and team shares (`ls`, `grep`, and the root listing all default to
`all_readable`). To narrow to just your own sources, pass `--owner me` /
`--owner current_user`. Use `--owner direct_shared` for incoming peer-to-peer
grants, `--owner team_shared` for incoming team-derived grants, or `--owner
shared` for both, always excluding the current user's own sources. `--owner
team` remains a legacy alias for `team_shared`. Pass a source-owner user ID or
email only when the user asks about that person. Direct sharers may not appear
in `nessie team list`; discover them from `nessie ls --owner direct_shared`
and the returned `sourceOwner` metadata.

Use `sourceOwner` on a returned descriptor as the **only** ownership and scoping
signal — it tells you whose source this is, not who semantically performed every
task mentioned inside it. Read the content before assigning work to a person.
Treat `integration` fields (`accountName`, `providerName`, `deviceId`, provider
labels) as provenance only; do not decide whether a result is "mine" or
"Tiger's" from an integration account email or display name, which can differ
from the authenticated Nessie owner.

## Incoming shares and collaborative contexts

```bash
nessie team list
nessie ls --owner direct_shared
nessie ls --owner team_shared
nessie ls --owner <teammate-user-id>
```

Use `team list` to resolve team-derived work and named teammates. For direct
shares, start with `ls --owner direct_shared`, because the sharer need not be a
team member. Then use `ls` with the returned `sourceOwner.userId` or email to
discover their browsable roots. Treat the IDs
returned by `ls` as authoritative for navigation. For "what did Tiger do
yesterday?", resolve Tiger's `userId`, then run `nessie ls --owner
<tiger-user-id> --since/--until` or `nessie grep "<topic>" --owner
<tiger-user-id> --since/--until`.

Do not use incoming shared roots as the default for first-person questions about
"me" or "my work"; personal roots are the primary scope for the authenticated
user.

The CLI reads the effective graph after sharing inheritance and exclusions are
applied. A shared integration may omit an excluded repository or session; a
directly shared session may appear independently of its parent. Do not infer
access from the parent row alone — list or read the target and use the returned
result as authoritative.

Shared context folders live inside the virtual Contexts root. Viewer access can
list and read the tree. Editor access also permits the authenticated user to
create or move their own contexts and folders into it; those nodes keep their
original owner. A folder can therefore contain mixed-owner children. Folder
deletion requires the folder to be empty across every contributor.

The CLI does not create, change, or remove sharing grants. If the user asks to
share or unshare a source, repository, session, context, or folder, explain the
effective scope and direct them to the Nessie app's Share control. Do not try to
simulate unsharing by deleting the underlying node or conversation.

## Reading: cat, head, tail

```bash
nessie cat <node-id>             # full content, no length cap
nessie head <node-id>            # first 10 lines
nessie head <node-id> -n 40      # first 40 lines (--lines also works)
nessie tail <node-id>            # last 10 lines
nessie tail <node-id> -n 40      # last 40 lines
```

`cat` prints a node's readable content as raw text — no JSON wrapper. It works
on contexts, Obsidian notes, Granola summaries, whole transcripts, and a single
chat message. It has **no length cap**: a long transcript prints in full.

`head` and `tail` print the first or last N lines (default 10) and read only
enough from that edge, so they are cheap on large transcripts where `cat` would
be expensive. Lines are faithful for both regular slice content (a note, one
message) and the special whole-chat-transcript case.

All three reject a pure container (e.g. an integration root) with an
"is a directory" error pointing you back to `ls`. For nodes that are both file
and directory, the read commands return the readable body.

Context Markdown can reference Nessie image assets. To inspect one, run `nessie asset get <asset-id-or-url>` and open the printed temporary file path with the host agent's image tool. To add one, run `nessie asset upload <context-id> <image-file>` and insert the returned Markdown image block into that context; upload separately for each context rather than reusing an asset.

## Searching: grep

```bash
nessie grep "<query>"                         # hybrid search, everything you can read
nessie grep "<query>" <parent-id>             # scope to a subtree
nessie grep "<query>" --type transcript
nessie grep "<query>" --type obsidian -F      # fixed-string (literal) match
nessie grep "<query>" --since 2026-05-30 --until 2026-05-31
nessie grep "<query>" --owner me              # narrow to just your own sources
nessie grep "<query>" --owner direct_shared   # peer-to-peer shares only
nessie grep "<query>" --owner team_shared     # team-derived shares only
nessie grep "<query>" --owner shared          # all incoming shares
nessie grep "<query>" --owner <teammate-user-id>
nessie grep "<query>" --repo .                 # only the current git repo
nessie grep "<query>" --repo github.com/org/repo
nessie grep "<query>" --limit 20
```

`grep` searches node content and is the recursive-search affordance: the
optional second positional argument is a parent UUID that scopes the search to
that node and all its descendants. It is the right tool for "find X anywhere
under this vault / root / folder" because there is no `find` yet.

It searches hybrid (semantic + keyword) by default. Hybrid is tuned for fuzzy,
conceptual queries and under-returns short exact-token lookups, so pass `-F` /
`--literal` for fixed-string matching whenever the query is a name, email, UUID,
error code, file path, other identifier, or an exact quoted wording the user
wants matched. Literal matches the whole query as one contiguous substring, so
split a multi-word natural-language request into salient exact terms instead of
treating it as one phrase. Deciding a query is a name or identifier lookup is
your call: when a default `grep` on a proper noun comes back thin, empty, or
matching only your own session, rerun it with `-F` before concluding Nessie has
nothing - that under-return is a search-mode artifact, not absence of data.
Results are grouped by document with the matching content and carry
`sourceOwner` for attribution. Cloud hits include an explicit
`sliceId: ... · modality: ...` line: keep using the header's node ID with `cat`,
and use `sliceId` only for a confirmed modality correction. `--json` preserves
the same fields as `sliceId` and nullable `modality`. `--limit` defaults to 10, max
500. `--type`, `--since`, `--until`, and `--owner` behave as for `ls`.

Search is a starting point, not an answer. One `grep` is rarely enough: vary the
wording and search related names and topics separately, and run several searches
(serially — see the caution below) before you conclude. For each relevant hit,
`cat` (or `head`/`tail` for long nodes) the full node before synthesizing — read
several matching sources, not just the first, and follow threads into the people,
events, and decisions they mention. Do not stop at the first node that confirms a
plausible answer; the fullest discussion is often not the top hit. A `grep` hit
also lands you in the middle of a conversation, not its conclusion: keep reading
the chunks that follow the match — `cat` the whole node, or page forward and
`tail` for the end — before you conclude. The resolution of a back-and-forth
comes after the matched chunk, sometimes a few messages later, sometimes in the
last messages. If a chunk cuts off mid-thought, read more of that node.

`--repo` narrows to specific git repos — pass a repo path (`.` for the repo you
are working in) or a canonical repoKey like `github.com/org/repo`; repeatable, or
comma-separated. It can only narrow, never widen. Because the repo identity lives
only on coding-session content, **any `--repo` filter excludes everything that
isn't tied to a git repo** (notes, meeting transcripts, profile sections). Use it
to scope a search to the code you are working on; drop it to search everything.

If `grep` reports `truncated: true`, the scope hit an internal safety cap before
searching; narrow it with a smaller `--since`/`--until` window, a more specific
parent UUID, or a narrower `--type`, then retry. `scopeNodeCount` reports how
many nodes were in scope.

Local CLI search does not support concurrent requests. Never fan out multiple
`nessie grep` commands in parallel — run them serially and wait for each to
finish. Concurrent local searches can slow each other enough to time out and may
be misreported as "Nessie is not running" even when the app is open.

## Agent Takeover / Resume

For "Nessie resume", "Nessie takeover", "resume this Claude/Codex session", or a
pasted conversation/node ID, treat resume as a search-then-read workflow.

If the user gives a UUID, read a small beginning window and the recent tail:

```bash
nessie head <id> -n 5
nessie tail <id> -n 40
```

If the user gives no ID, find candidates from their clue (title, error, branch,
file path, project), then read the match the same way:

```bash
nessie grep "<user-provided clue>" --type transcript
```

The handoff state usually lives near the **end** of a long transcript, so bias
toward `tail`. If the tail references specific files, branches, errors, or
decisions, `grep` those terms (scoped to the transcript or its root) and `cat`
the adjacent nodes. Produce a compact takeover brief — goal, current state,
files touched, decisions, blockers, next actions — before continuing the work.

## Profile Access and Updates

```bash
nessie profile
nessie profile get
nessie profile get --section connections
nessie profile edit-field --field <field> --value "<value>"
nessie profile edit-text --section <section> --content "<markdown>"
nessie profile edit-text --section <section> --content-file <path>
nessie profile add-card --section <section> --fields '{"key":"value"}'
nessie profile update-card --section <section> --index <n> --updates '{"key":"value"}'
nessie profile remove-card --section <section> --index <n>
```

Profile commands return or edit the user's structured profile. The profile may
still be building for new users, so describe this as accessing and updating
their profile rather than assuming every section is complete. `nessie profile`
or `nessie profile get` returns the full profile; `--section` reads one section.

For first-person questions ("what did I do", "what am I working on", "who am I"),
start with `nessie profile` or `nessie check-in` for orientation, then drill
into raw sources with `nessie ls` / `nessie grep` if the profile is sparse.
Sparse profile data does not mean sparse raw data.

Scalar fields for `edit-field`: `name`, `preferredName`, `dateOfBirth`, `email`,
`phone`, `address`, `employer`, `jobTitle`.

Text sections for `edit-text`: `biography`, `communication`, `personality`.
These accept full markdown that replaces the section.

Card sections for `add-card`, `update-card`, `remove-card`: `education`,
`workExperience`, `connections`, `projects`, `decisions`, `expertise`,
`upcoming`.

Card fields:

- `education`: `school`, `degree`, `years`, `description`
- `workExperience`: `employer`, `title`, `years`, `description`
- `connections`: `name`, `shortDescription`, `description`
- `projects`: `name`, `status`, `description`, `techStack`
- `decisions`: `title`, `description`, `category`, `timeHorizon`, `date`
- `expertise`: `name`, `category`, `description`
- `upcoming`: `title`, `date`, `category`, `description`

Cards are identified by 0-based index within their section. Run
`nessie profile get --section <section>` to see current cards and indices before
updating or removing. For `add-card`, provide all fields; for `update-card`,
include only the fields you want to change. Profile changes are immediately
visible in the Nessie app.

## Search Modality Corrections

```bash
nessie modality <slice-id> <invalid|stale|hypothetical|misattributed|ironic|clear>
```

Use the `sliceId` returned by cloud search. The command is cloud-only and
owner-only; a teammate's readable result cannot be corrected by the reader.
`clear` removes an existing correction. Invoke this command only when the user
explicitly approved this exact slice and value. If you suggested the change,
ask and wait; a direct user instruction naming the exact correction counts as
approval. When the user says a result is wrong, outdated, speculative,
misattributed, or nonliteral without naming a modality, infer the matching
value, show the excerpt and `sliceId`, and proactively offer to run the command;
do not run it until the user approves. There is intentionally no separate
confirmation flag.

## Writing: mkdir, tee, replace-lines, sed, mv, rm, rmdir, delete

```bash
nessie mkdir "<name>" [<parent-folder-id>] [--emoji "<emoji>"]
echo "<markdown>" | nessie tee "<title>" [--emoji "<emoji>"] [--folder <folder-id>] [--sources <uuid1> <uuid2> ...]
nessie tee "<title>" --from-file <path> [--emoji "<emoji>"] [--folder <folder-id>] [--sources <uuid1> ...]
nessie sed <id> --old "<text to find>" --new "<replacement>" [--all]
nessie sed <id> --old-file <path> --new-file <path> [--all]
nessie replace-lines <id> --old-line "<complete line>" --new-line "<replacement line>"
nessie replace-lines <id> --old-line "<complete line>" --delete
nessie replace-lines <id> --old-file <path> --new-file <path>
nessie mv <id> --to <folder-id>
nessie mv <id> --name "<new name>"
nessie mv <id> --unfiled
nessie rm <id>
nessie rmdir <folder-id>
nessie delete <conversation-id>
```

These write to the user's context library. Folders organize contexts; contexts
are the user's saved context documents.

- `mkdir` creates a folder. Pass an optional parent folder ID to nest it inside
  another folder; omit it to create at the top level. `rmdir` deletes an
  **empty** folder — move or delete its contents first.
- `tee` creates a context. The markdown body comes from **stdin** (pipe or
  heredoc) or from `--from-file`; prefer `--from-file` when the body contains
  apostrophes, asterisks, or backslashes to avoid shell escaping. Do not put the
  title as an H1 at the top of the body — titles are stored separately, so start
  with the first real section. Include an `--emoji` that represents the topic.
  Always pass `--sources` with the document UUIDs of every transcript and
  context you read while researching; this creates the provenance badges that
  let the user trace claims back to original conversations. Without `--sources`
  there is no source badge. The context is indexed for search automatically.
  When the body refers to another node, cross-reference it with an inline
  Markdown link whose label and destination are the same canonical URL —
  `[https://nessielabs.com/n/<uuid>](https://nessielabs.com/n/<uuid>)` — using
  a node UUID from earlier command output. Do not substitute a title in the
  label; Nessie derives current display metadata from the destination. The
  explicit link derives a "mentions" relationship. Inline
  links complement `--sources`: sources create the provenance badges, inline
  links make individual references navigable in place. This applies to `sed`
  and `replace-lines` edits too.
- `replace-lines` is the safe default for deleting or replacing complete lines,
  including Markdown table rows and list items. Pass each line with a repeated
  `--old-line` / `--new-line`, or use files for a multi-line block. Use
  `--delete` to remove the matched lines. The command validates one unique block
  of full lines and owns the adjacent newline, so deleting a row cannot leave a
  blank line that breaks a Markdown table.
- `sed` edits a context body by exact string replacement. Use it for inline
  fragments within a line. The match must be
  unique unless `--all` is set. Prefer `--old-file` / `--new-file` when the text
  contains markdown, dashes, or special characters. For multiline replacements
  or text containing newline characters, always use `--old-file` / `--new-file`.
  Do not encode line breaks as `\n` or `\\n` in inline `--old` / `--new`
  arguments; the CLI treats those sequences literally. Only contexts can be
  edited; transcripts and other documents cannot be edited (though a whole
  conversation can be deleted — see `delete`).
- Context body, title, and emoji are collaborative fields. For a shared context
  or one already enrolled in collaboration, `cat`, `head`, and `tail` read the
  synchronized document; `replace-lines`, `sed`, and the title/emoji forms of
  `mv` update that same document. A private never-enrolled context can still use
  the legacy local write path when Cloud Sync is off and no collaborative
  checkpoint exists. The context owner and users with effective Editor access
  can write; Viewer access can only read. An edit may therefore target a
  teammate-owned context when its personal or team grant permits editing.
- After `replace-lines` or `sed` succeeds, run `nessie cat <id>` and verify the
  changed section in the canonical context. A write confirmation alone is not a
  content readback.
- `mv` moves a context or folder into a folder (`--to`), renames it (`--name`),
  or removes it from its parent (`--unfiled`). Provide exactly one. Moving a
  folder into itself or one of its descendants is rejected. An Editor shared
  folder is a valid destination for caller-owned contexts and folders; a Viewer
  folder rejects writes. Moving changes containment, not node ownership.
- `rm` deletes a context by ID.
- `delete` deletes a synced conversation/transcript by ID: it removes the chat
  from the library and excludes it from future syncs so it is not re-imported.
  This is the one command that removes synced source material, so it is gated by
  an interactive terminal confirmation (it shows what will be removed and prompts
  before deleting) and requires a TTY. Use it only when the user explicitly asks
  to delete a specific chat — never to tidy up. It is distinct from `rm`, which
  is for contexts.

## CLI-Specific Cautions

Track source document IDs as you read; pass them with `--sources` when creating
contexts from Nessie research.

All read commands are instant local reads. Context creation is an instant local
write plus async embedding. All data is local to the user's machine; Nessie does
not send documents to external services for CLI reads and writes.

Transcripts cannot be edited. Do not try to modify synced conversation
documents. A whole conversation can be deleted with `nessie delete` when the user
explicitly asks to remove that chat, but its contents are never edited in place.
