---
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 generate 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 — both the user's own work and
their team's. It gives agents unified access to what the user (and, in team
scope, their teammates) 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. In team scope I can do the same across the sources
> your teammates have shared with you - answer what the team has 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 generate 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. Context generation is
one powerful capability, not the only way to use Nessie.

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.

## Default User Experience

When a user asks what Nessie can do, explain that Nessie gives agents access
to the context they and their team have already built. Give generic examples of
normal back-and-forth use, spanning both the user's own work and their team's
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?"
- "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."

Team examples resolve against the sources teammates have shared with the user;
when the surface exposes owner scoping, keep first-person questions scoped to
the user and widen to team-shared sources for the team-oriented ones. It is fine
to show a command or tool table when it helps the user understand the tooling.
Do not frame context generation 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; context
generation is for deeper or reusable outputs.

## 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 team-shared roots as the default scope for first-person questions.
Use team and team-shared roots when the user asks about a teammate by name,
asks about shared team 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. Pass an explicit
teammate identifier or teammate email when the user asks for that person's
sources. Use `team` for teammate-owned shared sources excluding the current
user, and `all_readable` for the current user's sources plus team-shared
sources.

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.

## 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.
- 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.

## Generated vs Manual Research

Generated context research is available only on surfaces that expose Nessie's
backend generation workflow, such as the app and CLI. Adapter-specific
instructions may narrow this guidance when a surface does not expose that
workflow.

Use generated context research when:

- The user wants a comprehensive brief, memo, summary, or prep doc grounded
  purely in their conversation history.
- The task needs synthesis across their overall history or profile, and manual
  search is likely to overfit to granular transcript citations.
- You need higher-accuracy synthesis from Nessie's backend research agent.
- The user pushes back on manual output quality after multiple rounds.

Use the manual research workflow when:

- You need to combine Nessie data with external information or code context.
- You want to control exactly which sources are consulted.
- You are answering a question directly in the agent session and need to search,
  read, and synthesize from Nessie sources before responding.
- You are creating a context that synthesizes across Nessie data and other
  sources such as files, web, or codebase context.

Both workflows have the same source authority rules. Manual research gives you
control over exactly which sources to read and how to synthesize them. Use
pagination when reading long transcripts rather than loading everything at once.
Generated context research re-runs research from scratch, so treat it as a
deliberate escalation for deeper synthesis rather than the default next step
after every manual answer.

Never search once, skim snippets, and save a context. This produces thin,
unreliable output that misses critical details the user expects.

Do not keep forcing a manual answer after the user has pushed back on quality.
If the task needs deeper synthesis or the user is not satisfied after multiple
rounds, use a generated research workflow when available and incorporate that
output.

## 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.

## 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 Nessie macOS app over localhost and reads or writes the
app's local data. The app 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 | `sed` — string-replace a context body |
| `stat` — metadata only, no body | `mv` — move / rename / unfile a context |
| `grep` — search content in a subtree | `rm` — delete a context |
| | `rmdir` — delete an empty folder |
| | `delete` — delete a synced conversation |
| | `generate` — research-and-create a context |

`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.

## 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.

## 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 team                      # teammate-owned shared roots only
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 team-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. 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. "Team-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 team`,
distinguished by the `owner` column (a teammate's email). To find shared
contexts, open the Contexts root and look for rows owned by a teammate, then
drill in - do not conclude from the top-level root list alone that no shared
contexts exist.

`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` only when one of your own sources is shared with your
team; its value is a bounded headline of the audience - a team name,
`<team> admins`, a teammate, or `+N` when there are more. A context inside a
shared folder inherits that folder's audience, so it is not blank. The column is
absent when nothing in the listing is shared out, so a missing `shared` column
means none of these sources are shared, not that sharing is unknown. Whole-team
and admin-only shares are reflected reliably; a grant made to one specific person
may not appear, depending on team-directory scoping. Copy the `id` to read,
search, or list deeper.

`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`,
  `granola`) or a raw node kind (`claude_code_chat`, `codex_chat`,
  `obsidian_note`, `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.
- `--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 team-shared (`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 team` for teammate-owned shared sources
excluding the current user. Pass a teammate user ID or email
(`--owner tiger@nessielabs.com`) only when the user asks about that teammate's
sources. To resolve a named teammate, run `nessie team list`, then pass the
member `userId` with `--owner`. Email selectors resolve only from existing
team-member email metadata; an unknown email returns an invalid-input error
rather than empty results.

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.

## Teams

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

Use `team list` to resolve team-shared work and named teammates, then use `ls`
with that member's `userId` 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 team-shared roots as the default for first-person questions about
"me" or "my work"; personal roots are the primary scope for the authenticated
user.

## 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 team            # teammate-owned shared sources
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. `--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.

## Writing: mkdir, tee, 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 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.
- `sed` edits a context body by exact string replacement. 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`).
- `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.
- `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.

## generate

```bash
nessie generate "<prompt>"
```

`generate` has Nessie's backend research agent search the user's conversation
history and synthesize a structured context automatically. This takes 30-120
seconds. The backend agent generally produces higher-quality deep synthesis than
a manual workflow because it is optimized for context research and attribution.
Use it for comprehensive briefs, memos, or profile/history-level synthesis, or
when manual answers are not reaching the right abstraction. Because it re-runs
research from scratch, treat it as a deliberate escalation, not a default retry.

## 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.
