feat(app): add Settings view, configurable claude dir, and recap docs refactor
Introduce a Settings view for configuring the Claude data directory (with WSL auto-detection on Windows), sidebar project grouping module, and an empty-state onboarding screen for SessionList. Refactor recap-patterns.md into per-card reference files under references/recap/ with separate retrieval and writing guides. Remove the legacy panel.html. On the data layer: incremental indexing via changedPaths, per-session live-update IPC (obelisk:session-updated), and session dirty-tracking in the renderer.
This commit is contained in:
@@ -1,508 +1,9 @@
|
||||
# Obelisk Recap Patterns
|
||||
# Obelisk Recap Retrieval Patterns
|
||||
|
||||
Use this when Obelisk Intent Routing sends the `recap` intent. In practice,
|
||||
that means the first word after `/obelisk` is `recap`; everything after it is
|
||||
the recap target.
|
||||
Compatibility pointer.
|
||||
|
||||
Do not self-trigger this reference from broad weekly/monthly summaries, charts,
|
||||
rankings, shareable-card language, or playlist-style metaphors. Those are target
|
||||
details only after the explicit `recap` intent has already selected this file.
|
||||
|
||||
This is an optional app handoff pattern. Obelisk stays agent-first: the agent
|
||||
queries sessions and memories, judges what matters, then fills card content.
|
||||
The app owns rendering, layout, export, and animation.
|
||||
|
||||
## Common Period Targets
|
||||
|
||||
Treat the target after `recap` as normal user language. Common app-generated
|
||||
targets:
|
||||
|
||||
- `/obelisk recap this week` -- the current calendar week in the user's timezone.
|
||||
- `/obelisk recap last week` -- the previous calendar week.
|
||||
- `/obelisk recap this month` -- the current calendar month.
|
||||
- `/obelisk recap last month` -- the previous calendar month.
|
||||
|
||||
Use the current date and timezone from the runtime/session context when
|
||||
available. If the target contains extra style language, keep the period meaning
|
||||
and treat the rest as presentation guidance.
|
||||
|
||||
## Contract
|
||||
|
||||
- Produce card content, not HTML, CSS, SVG, or layout instructions.
|
||||
- Keep the first result share-safe. Avoid secrets, tokens, private URLs, long
|
||||
absolute paths, raw tool outputs, and embarrassing private text unless the
|
||||
user asked for private analysis.
|
||||
- Concrete numbers, exact times, quotes, and verdicts need evidence. If you
|
||||
cannot support a detail, omit it or soften it.
|
||||
- Memory is prior notes, not ground truth. If a card uses a memory conclusion,
|
||||
say in prose that it came from a prior memory when answering in chat, and add
|
||||
`memory_id` evidence when producing JSON.
|
||||
- Do not propose a durable memory just because you generated a recap. Propose
|
||||
memory only if the retrieval reveals a reusable cross-session conclusion not
|
||||
already covered by `memories()`.
|
||||
|
||||
## Retrieval Shape
|
||||
|
||||
Start with orientation and bounded evidence. Use English memory queries even
|
||||
when the recap text will be in another language.
|
||||
|
||||
```js
|
||||
const period = {
|
||||
label: 'Week 24',
|
||||
after: '2026-06-08T00:00:00+08:00',
|
||||
before: '2026-06-15T00:00:00+08:00',
|
||||
timezone: 'Asia/Shanghai',
|
||||
};
|
||||
|
||||
const map = overview({ limit: 8 });
|
||||
const project = map.current.project?.project;
|
||||
const scoped = project ? { project } : {};
|
||||
|
||||
return {
|
||||
current: map.current,
|
||||
current_project: map.current_project,
|
||||
prior_memories: memories({
|
||||
...scoped,
|
||||
query: 'weekly recap project decisions workflows debugging shipping',
|
||||
limit: 8,
|
||||
}).map(m => ({
|
||||
id: m.id,
|
||||
path: m.path,
|
||||
anchors: m.anchors,
|
||||
session_id: m.session_id,
|
||||
created_at: m.created_at,
|
||||
summary: m.summary?.slice(0, 280),
|
||||
})),
|
||||
sessions: sessions({
|
||||
...scoped,
|
||||
after: period.after,
|
||||
before: period.before,
|
||||
limit: 40,
|
||||
}).map(s => ({
|
||||
id: s.id,
|
||||
title: s.title,
|
||||
project: s.project,
|
||||
branch: s.git_branch,
|
||||
started_at: s.started_at,
|
||||
ended_at: s.ended_at,
|
||||
message_count: s.message_count,
|
||||
})),
|
||||
summaries: summaries({
|
||||
...scoped,
|
||||
after: period.after,
|
||||
before: period.before,
|
||||
limit: 30,
|
||||
}).map(s => ({
|
||||
id: s.id,
|
||||
session_id: s.session_id,
|
||||
session_title: s.session_title,
|
||||
project: s.project,
|
||||
timestamp: s.timestamp,
|
||||
snippet: s.content?.slice(0, 260),
|
||||
})),
|
||||
workflows: workflows({
|
||||
...scoped,
|
||||
after: period.after,
|
||||
before: period.before,
|
||||
limit: 20,
|
||||
}).map(w => ({
|
||||
run_id: w.run_id,
|
||||
session_id: w.session_id,
|
||||
name: w.workflow_name,
|
||||
status: w.status,
|
||||
agent_count: w.agent_count,
|
||||
tokens: w.total_tokens,
|
||||
timestamp: w.timestamp,
|
||||
})),
|
||||
failures: failures({
|
||||
...scoped,
|
||||
after: period.after,
|
||||
before: period.before,
|
||||
limit: 12,
|
||||
}).map(f => ({
|
||||
session_id: f.session_id,
|
||||
session_title: f.session_title,
|
||||
tool: f.tool_name,
|
||||
timestamp: f.timestamp,
|
||||
snippet: f.content?.slice(0, 180),
|
||||
})),
|
||||
};
|
||||
```
|
||||
|
||||
Use SQL for exact aggregate numbers after the helper-first pass has established
|
||||
the scope. Keep meta rows out of ordinary user-visible counts.
|
||||
|
||||
```js
|
||||
const project = '%quiet-zero%';
|
||||
const after = '2026-06-08T00:00:00+08:00';
|
||||
const before = '2026-06-15T00:00:00+08:00';
|
||||
|
||||
const metrics = sql(`
|
||||
SELECT
|
||||
COUNT(DISTINCT s.id) AS sessions,
|
||||
COUNT(m.uuid) AS messages,
|
||||
COALESCE(SUM(COALESCE(m.input_tokens, 0) + COALESCE(m.output_tokens, 0)), 0) AS tokens,
|
||||
COUNT(DISTINCT substr(m.timestamp, 1, 10)) AS active_days
|
||||
FROM sessions s
|
||||
LEFT JOIN messages m ON m.session_id = s.id
|
||||
WHERE s.project LIKE ?
|
||||
AND COALESCE(m.is_meta, 0) = 0
|
||||
AND m.timestamp >= ?
|
||||
AND m.timestamp < ?
|
||||
`, project, after, before)[0];
|
||||
|
||||
const user_messages = sql(`
|
||||
SELECT
|
||||
m.uuid,
|
||||
m.session_id,
|
||||
s.title AS session_title,
|
||||
m.timestamp,
|
||||
substr(m.text, 1, 500) AS text
|
||||
FROM messages m
|
||||
JOIN sessions s ON s.id = m.session_id
|
||||
WHERE s.project LIKE ?
|
||||
AND m.type = 'user'
|
||||
AND m.content_type = 'text'
|
||||
AND COALESCE(m.is_meta, 0) = 0
|
||||
AND m.timestamp >= ?
|
||||
AND m.timestamp < ?
|
||||
ORDER BY m.timestamp
|
||||
LIMIT 300
|
||||
`, project, after, before);
|
||||
|
||||
return { metrics, user_messages };
|
||||
```
|
||||
|
||||
## Archetypes
|
||||
|
||||
Choose one dominant archetype from the evidence. Do not force all cards to match
|
||||
it; the archetype is the cover persona and tone baseline.
|
||||
|
||||
| archetype | essential action | tone baseline |
|
||||
|---|---|---|
|
||||
| `architect` | establishes structure, boundaries, and systems from above | matter-of-fact, structural pride |
|
||||
| `debugger` | loops through symptoms until root cause becomes visible | wry, weary, occasional dark humor |
|
||||
| `shipper` | keeps pushing forward with dense cadence | energetic, slightly breathless |
|
||||
| `curator` | collects, organizes, refines, and distills | reflective, low-key clarity |
|
||||
| `director` | coordinates many threads from the center outward | observant, slight remove |
|
||||
| `cartographer` | reorganizes known structure, redraws maps, moves boundaries | patient, surveyor-like |
|
||||
| `wanderer` | crosses projects without one obvious center, leaving traces | gentle, accepting, no apology |
|
||||
|
||||
Selection hints:
|
||||
|
||||
- Use `architect` when the week is dominated by system design, APIs, schemas,
|
||||
boundaries, or core concepts.
|
||||
- Use `debugger` when repeated failures, false positives, regressions, or root
|
||||
cause hunts dominate.
|
||||
- Use `shipper` when the evidence shows sustained implementation velocity,
|
||||
builds, releases, or many completed edits.
|
||||
- Use `curator` when the work is mostly cleanup, documentation, memory,
|
||||
organization, or taste/refinement.
|
||||
- Use `director` when workflows, subagents, review loops, or multi-agent
|
||||
coordination are the main story.
|
||||
- Use `cartographer` when the user moves modules, redraws information
|
||||
architecture, re-scopes boundaries, or turns "this lives here" into "this
|
||||
belongs there".
|
||||
- Use `wanderer` when the period spans many unrelated projects and the honest
|
||||
story is exploratory rather than centered.
|
||||
|
||||
## JSON Shape
|
||||
|
||||
The schema is deliberately card-content oriented. Keep keys stable, but let
|
||||
strings carry the style. Card text can use the user's language; field names stay
|
||||
English.
|
||||
|
||||
For weekly recaps, `metrics.active_days` and cover `activity` should contain 7
|
||||
numbers ordered Monday through Sunday, where `0` means no visible activity and
|
||||
`1` means active. For monthly recaps, use one value per calendar day in the
|
||||
period, or omit the field if the evidence is too thin.
|
||||
|
||||
```ts
|
||||
type Recap = {
|
||||
schema_version: "obelisk.recap.v1";
|
||||
kind: "weekly" | "monthly";
|
||||
generated_at: string;
|
||||
|
||||
period: {
|
||||
label: string;
|
||||
start: string;
|
||||
end: string;
|
||||
timezone: string;
|
||||
};
|
||||
|
||||
source: {
|
||||
project?: string;
|
||||
session_ids: string[];
|
||||
memory_ids?: string[];
|
||||
};
|
||||
|
||||
metrics: {
|
||||
sessions?: number;
|
||||
messages?: number;
|
||||
tokens?: number;
|
||||
active_days?: number[];
|
||||
streak_days?: number;
|
||||
workflows?: number;
|
||||
workflow_agents?: number;
|
||||
corrections?: number;
|
||||
};
|
||||
|
||||
persona: {
|
||||
archetype:
|
||||
| "architect"
|
||||
| "debugger"
|
||||
| "shipper"
|
||||
| "curator"
|
||||
| "director"
|
||||
| "cartographer"
|
||||
| "wanderer";
|
||||
title: string;
|
||||
subtitle: string;
|
||||
tone: string;
|
||||
};
|
||||
|
||||
cards: [
|
||||
CoverCard,
|
||||
ThinkingPathCard,
|
||||
VibeCard,
|
||||
WorkflowOrToolsCard,
|
||||
ClosingCard
|
||||
];
|
||||
|
||||
evidence?: Evidence[];
|
||||
};
|
||||
```
|
||||
|
||||
### Card 1: Cover
|
||||
|
||||
```ts
|
||||
type CoverCard = {
|
||||
type: "cover";
|
||||
badge: string;
|
||||
title: string;
|
||||
subtitle: string;
|
||||
activity: number[];
|
||||
footer: string;
|
||||
evidence_refs?: string[];
|
||||
};
|
||||
```
|
||||
|
||||
Use the cover to name the period and the persona. The title can be an archetype
|
||||
label such as "The Architect"; the subtitle should summarize the period's real
|
||||
dominant work in one line.
|
||||
|
||||
### Card 2: Thinking Path
|
||||
|
||||
```ts
|
||||
type ThinkingPathCard = {
|
||||
type: "thinking_path";
|
||||
title: string;
|
||||
items: Array<{
|
||||
day: string;
|
||||
prompt: string;
|
||||
outcome: string;
|
||||
evidence_refs?: string[];
|
||||
}>;
|
||||
};
|
||||
```
|
||||
|
||||
Pick 3-6 turning points. A `prompt` is the question, friction, or task that
|
||||
started the path. An `outcome` is the decision, fix, or learned framing.
|
||||
|
||||
### Card 3: Vibe
|
||||
|
||||
```ts
|
||||
type VibeCard = {
|
||||
type: "vibe";
|
||||
title: string;
|
||||
observations: Array<{
|
||||
label: string;
|
||||
text: string;
|
||||
count?: number;
|
||||
time?: string;
|
||||
evidence_refs?: string[];
|
||||
}>;
|
||||
meter?: {
|
||||
label: string;
|
||||
value: number;
|
||||
caption: string;
|
||||
};
|
||||
quote?: {
|
||||
text: string;
|
||||
caption?: string;
|
||||
evidence_refs?: string[];
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
This card can be playful, but it must stay grounded. Repeated phrases should be
|
||||
counted from visible user messages, not meta messages or tool results.
|
||||
|
||||
### Card 4: Workflows Or Tools
|
||||
|
||||
```ts
|
||||
type WorkflowOrToolsCard = {
|
||||
type: "workflow" | "tool_habits" | "debugging" | "shipping";
|
||||
title: string;
|
||||
summary?: string;
|
||||
stats?: string;
|
||||
items: Array<{
|
||||
name: string;
|
||||
outcome: string;
|
||||
evidence_refs?: string[];
|
||||
}>;
|
||||
verdict: string;
|
||||
};
|
||||
```
|
||||
|
||||
Choose the card type that best fits the period. Use `workflow` when workflow
|
||||
runs or subagents are the story; `debugging` when failures and fixes dominate;
|
||||
`shipping` when completed implementation dominates; `tool_habits` when the
|
||||
period is mostly about how the user worked.
|
||||
|
||||
### Card 5: Closing
|
||||
|
||||
```ts
|
||||
type ClosingCard = {
|
||||
type: "closing";
|
||||
headline: string;
|
||||
stats: string[];
|
||||
most_said_phrase?: string;
|
||||
signoff: string;
|
||||
evidence_refs?: string[];
|
||||
};
|
||||
```
|
||||
|
||||
Close with one high-signal stat and a short signoff. Avoid turning the closing
|
||||
card into a second summary.
|
||||
|
||||
### Evidence
|
||||
|
||||
```ts
|
||||
type Evidence = {
|
||||
id: string;
|
||||
session_id?: string;
|
||||
message_uuid?: string;
|
||||
memory_id?: string;
|
||||
summary?: string;
|
||||
};
|
||||
```
|
||||
|
||||
Evidence is for local traceability and app inspection. It does not have to be
|
||||
shown on exported cards. Prefer short summaries over raw snippets.
|
||||
|
||||
## Output Rules
|
||||
|
||||
- If the user asks for app handoff, return one JSON object and no surrounding
|
||||
prose.
|
||||
- If the user asks conversationally, answer with the card content naturally and
|
||||
include JSON only if useful.
|
||||
- Keep `cards.length === 5` in the order above.
|
||||
- Do not include unsupported cards just to fill space. It is better to make a
|
||||
quieter card than to invent drama.
|
||||
- Do not include raw SQL, query scripts, or private evidence in the shareable
|
||||
card text.
|
||||
|
||||
## Minimal Example
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": "obelisk.recap.v1",
|
||||
"kind": "weekly",
|
||||
"generated_at": "2026-06-13T03:40:00+08:00",
|
||||
"period": {
|
||||
"label": "Week 24",
|
||||
"start": "2026-06-08",
|
||||
"end": "2026-06-14",
|
||||
"timezone": "Asia/Shanghai"
|
||||
},
|
||||
"source": {
|
||||
"project": "quiet-zero",
|
||||
"session_ids": ["sid-a", "sid-b"],
|
||||
"memory_ids": ["mem-a"]
|
||||
},
|
||||
"metrics": {
|
||||
"sessions": 12,
|
||||
"messages": 847,
|
||||
"tokens": 2400000,
|
||||
"active_days": [1, 1, 1, 0, 1, 1, 1],
|
||||
"workflows": 3,
|
||||
"workflow_agents": 42
|
||||
},
|
||||
"persona": {
|
||||
"archetype": "architect",
|
||||
"title": "The Architect",
|
||||
"subtitle": "Designed a memory system from raw sessions to durable notes.",
|
||||
"tone": "matter-of-fact, structural pride"
|
||||
},
|
||||
"cards": [
|
||||
{
|
||||
"type": "cover",
|
||||
"badge": "Week 24",
|
||||
"title": "The Architect",
|
||||
"subtitle": "Designed a full memory layer without turning sessions into a wiki.",
|
||||
"activity": [1, 1, 1, 0, 1, 1, 1],
|
||||
"footer": "12 sessions - 2.4M tokens",
|
||||
"evidence_refs": ["e1", "e2"]
|
||||
},
|
||||
{
|
||||
"type": "thinking_path",
|
||||
"title": "Your thinking path",
|
||||
"items": [
|
||||
{
|
||||
"day": "Mon",
|
||||
"prompt": "Why compile sessions into a wiki?",
|
||||
"outcome": "Kept raw SQLite as the evidence layer.",
|
||||
"evidence_refs": ["e1"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "vibe",
|
||||
"title": "Your vibe this week",
|
||||
"observations": [
|
||||
{
|
||||
"label": "Catchphrase",
|
||||
"text": "This is too ugly.",
|
||||
"count": 4,
|
||||
"evidence_refs": ["e3"]
|
||||
}
|
||||
],
|
||||
"meter": {
|
||||
"label": "Patience",
|
||||
"value": 0.8,
|
||||
"caption": "saint"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "workflow",
|
||||
"title": "Are you a Workflow Enjoyer?",
|
||||
"stats": "3 workflows - 42 agents",
|
||||
"items": [
|
||||
{
|
||||
"name": "hono-plugin-review",
|
||||
"outcome": "perfect",
|
||||
"evidence_refs": ["e4"]
|
||||
}
|
||||
],
|
||||
"verdict": "Mostly tolerated"
|
||||
},
|
||||
{
|
||||
"type": "closing",
|
||||
"headline": "19 day streak",
|
||||
"stats": ["847 messages exchanged"],
|
||||
"most_said_phrase": "Okay, start doing it.",
|
||||
"signoff": "See you next week.",
|
||||
"evidence_refs": ["e5"]
|
||||
}
|
||||
],
|
||||
"evidence": [
|
||||
{
|
||||
"id": "e1",
|
||||
"session_id": "sid-a",
|
||||
"message_uuid": "msg-a",
|
||||
"summary": "The user chose raw SQLite as the evidence layer."
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
The `/obelisk recap` flow now starts at `references/recap/overview.md`.
|
||||
Do not use this as an all-in-one retrieval document. The current flow is
|
||||
card-by-card: read the overview, then for each card read its `patternN-*.md`,
|
||||
retrieve that card's evidence, read its `writingN-*.md`, and update the JSON
|
||||
before moving on.
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Obelisk Recap Writing
|
||||
|
||||
Compatibility pointer.
|
||||
|
||||
The `/obelisk recap` writing contract now lives in the per-card writing files
|
||||
under `references/recap/`, coordinated by `references/recap/overview.md`.
|
||||
Read the overview first. Then use each per-card writing file immediately after
|
||||
that card's retrieval pattern, rather than loading one large writing prompt.
|
||||
@@ -0,0 +1,74 @@
|
||||
# Obelisk Recap Overview
|
||||
|
||||
Use this only when the first word after `/obelisk` is `recap`. Everything after
|
||||
`recap` is the target period or style hint.
|
||||
|
||||
## Highest Priority: Phase Loop
|
||||
|
||||
This workflow is sequential. Do not preload all recap files. Do not gather all
|
||||
evidence first and write all cards at the end.
|
||||
|
||||
Follow this loop exactly:
|
||||
|
||||
1. Resolve the target period from the user's phrase.
|
||||
2. Run only a tiny orientation pass such as `overview({ limit: 6 })`.
|
||||
3. For Card 1, read `pattern1-cover.md`.
|
||||
4. Retrieve only Card 1 evidence.
|
||||
5. Read `writing1-cover.md`.
|
||||
6. Update/write the JSON for Card 1 now.
|
||||
7. Only after the JSON is updated, move to Card 2 and repeat.
|
||||
|
||||
Card order:
|
||||
|
||||
| card | retrieve | write |
|
||||
|---|---|---|
|
||||
| 1 cover | `pattern1-cover.md` | `writing1-cover.md` |
|
||||
| 2 thinking | `pattern2-thinking.md` | `writing2-thinking.md` |
|
||||
| 3 vibe | `pattern3-vibe.md` | `writing3-vibe.md` |
|
||||
| 4 workflow | `pattern4-workflow.md` | `writing4-workflow.md` |
|
||||
| 5 closing | `pattern5-closing.md` | `writing5-closing.md` |
|
||||
|
||||
The per-card files own retrieval details, JSON field duties, and card-specific
|
||||
taste. Do not move those concerns back into this file.
|
||||
|
||||
## Period Targets
|
||||
|
||||
- `this week`, `last week`: calendar week in the user's runtime timezone.
|
||||
- `this month`, `last month`: calendar month in the user's runtime timezone.
|
||||
|
||||
Do not infer timezone from examples, UTC suffixes, or file timestamps when
|
||||
runtime/session timezone is available.
|
||||
|
||||
## Overall Deck Taste
|
||||
|
||||
This is a Spotify Wrapped-like set of personal share cards: concise, designed,
|
||||
slightly playful, and built to make the user's work feel seen.
|
||||
|
||||
Do not criticize the user. Do not scold, diagnose, rank their personality, or
|
||||
turn friction into a performance review.
|
||||
|
||||
Use designed English chrome where it feels like card UI: week/month labels,
|
||||
archetype labels, compact stats, verdict seals, and signoffs. Preserve the
|
||||
user's own language for prompts, quotes, catchphrases, and reactions. This is
|
||||
not a translation task.
|
||||
|
||||
The deck should feel like a small artifact from someone who noticed the week,
|
||||
not a report generated from a database.
|
||||
|
||||
## Archetypes
|
||||
|
||||
Choose one dominant archetype from the period's dominant attention, not from the
|
||||
current recap-generation session.
|
||||
|
||||
| archetype | when it fits | tone baseline |
|
||||
|---|---|---|
|
||||
| `architect` | structure, boundaries, schema, systems | matter-of-fact structural pride |
|
||||
| `debugger` | symptoms, false positives, root-cause loops | wry and bug-comfortable |
|
||||
| `shipper` | dense implementation cadence | energetic but not breathless |
|
||||
| `curator` | organization, memory, docs, refinement | reflective and precise |
|
||||
| `director` | workflows, subagents, orchestration | observant from a slight remove |
|
||||
| `cartographer` | moving boundaries and redrawing maps | patient and surveyor-like |
|
||||
| `wanderer` | many projects without one center | gentle, exploratory |
|
||||
|
||||
If two fit, pick the one that describes what the user spent more thinking time
|
||||
on, not what shipped.
|
||||
@@ -0,0 +1,36 @@
|
||||
# Card 1 Cover Retrieval
|
||||
|
||||
Goal: choose the recap's dominant claim, persona, activity shape, and compact
|
||||
footer. The cover is not a topic inventory; it is one glanceable claim about
|
||||
what the period felt like.
|
||||
|
||||
Use the period from `overview.md`. Start from `overview({ limit: 6 })`, then
|
||||
look at in-period sessions, summaries, memories, and any obvious project scope.
|
||||
If the user asked for a project, keep that scope; otherwise prefer the current
|
||||
project only when the evidence makes it the clear center.
|
||||
|
||||
Prefer helpers first. If you need custom SQL for activity, token/message counts,
|
||||
or source-session scope, read `references/schema.md` before writing the SQL.
|
||||
|
||||
Retrieve:
|
||||
|
||||
- dominant claim: one thing that defined the period, supported by raw evidence;
|
||||
- persona: which archetype best matches the user's attention;
|
||||
- source sessions and memories used by this cover claim;
|
||||
- activity: weekly day intensities or monthly day intensities when supported;
|
||||
- footer: compact public metric such as sessions, messages, or tokens.
|
||||
|
||||
Avoid:
|
||||
|
||||
- a claim that lists three topics;
|
||||
- an archetype chosen from the recap-generation session itself;
|
||||
- footer caveats like excluded projects, exact SQL filters, or long session names;
|
||||
- making the cover a workflow metric when the week was really about a decision.
|
||||
|
||||
Read this card's writing file immediately after the cover evidence is stable:
|
||||
`references/recap/writing1-cover.md`. Then update the JSON fields
|
||||
`period`, `source`, `metrics`, `persona`, and the first `cards[]` entry.
|
||||
Do not read `pattern2-thinking.md` until this JSON update is done.
|
||||
|
||||
Stop when the cover has one evidence-backed dominant claim, one chosen persona,
|
||||
one metric scope, and at least one `evidence` anchor.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Card 2 Thinking Retrieval
|
||||
|
||||
Goal: find turning points. This card is not a project timeline and not an implementation log. It is the record of what changed in the user's mind.
|
||||
|
||||
Retrieve 3-6 turns. A turn needs both sides:
|
||||
|
||||
- the user question, friction, doubt, or request that started the turn;
|
||||
- the later decision, reframing, finding, or constraint that replaced the earlier
|
||||
state.
|
||||
|
||||
Useful searches:
|
||||
|
||||
- user questions in the period: "为什么", "是不是", "怎么", "我觉得", "不应该";
|
||||
- places where the user corrected the direction and then approved a new frame;
|
||||
- summaries that name decisions, followed by `context()` or `thread()` for the
|
||||
user's actual words;
|
||||
- memory records only as hints; raw session evidence must provide the prompt and
|
||||
turn.
|
||||
|
||||
Prefer helpers first. If you need custom SQL for message windows or user-turn
|
||||
counts, read `references/schema.md` before writing the SQL.
|
||||
|
||||
Do not use workflow names, feature names, or agent task labels as prompts when
|
||||
the user had their own wording. Do not use counts, "5 rounds", "13 agents", or
|
||||
implementation effort as turns unless that count is the turn itself.
|
||||
|
||||
Read this card's writing file immediately after the turns are chosen:
|
||||
`references/recap/writing2-thinking.md`. Then update the JSON `thinking_path`
|
||||
card and add evidence for each item.
|
||||
Do not read `pattern3-vibe.md` until this JSON update is done.
|
||||
|
||||
Stop when each item has a source-language prompt label, a short changed-state
|
||||
prompt, turn, and an `evidence` anchor.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Card 3 Vibe Retrieval
|
||||
|
||||
Goal: find small human signals in visible user messages. Vibe is not a correction log, not bracketed runtime text, and not a psychological profile.
|
||||
|
||||
Look for:
|
||||
|
||||
- catchphrases and repeated tiny reactions;
|
||||
- unusually blunt praise or rejection;
|
||||
- late-night disbelief, jokes, or rituals;
|
||||
- one quotable sentence that captures the period's character.
|
||||
|
||||
Only count visible user messages. Helper APIs omit meta by default, but custom
|
||||
SQL for phrase counts must filter user text with `COALESCE(m.is_meta,0)=0` and
|
||||
`m.content_type='text'`. Do not count tool results, injected command envelopes,
|
||||
UI labels, or bracketed runtime strings.
|
||||
|
||||
Useful retrieval:
|
||||
|
||||
- targeted phrase counts after you notice a likely catchphrase;
|
||||
- `thread(sessionId)` around high-energy moments;
|
||||
- `search()` for exact phrases, then `context()` for timing;
|
||||
- a bounded SQL count only after reading `references/schema.md`.
|
||||
|
||||
Read this card's writing file immediately after you have the small user signals:
|
||||
`references/recap/writing3-vibe.md`. Then update the JSON `vibe` card and add
|
||||
evidence for every quote, count, and timestamp.
|
||||
Do not read `pattern4-workflow.md` until this JSON update is done.
|
||||
|
||||
Stop when every observation is either exact user words or a tiny label backed by
|
||||
exact user words.
|
||||
@@ -0,0 +1,41 @@
|
||||
# Card 4 Workflow Retrieval
|
||||
|
||||
Goal: find actual workflow runs and how the user received them. Card 4 is about
|
||||
orchestration as experienced by the user, not an agent performance table.
|
||||
|
||||
Workflow rows have their own `workflows.timestamp`. During this card's retrieval,
|
||||
call `workflows({ project: projectLike, after, before })` before concluding the
|
||||
period had zero workflows.
|
||||
|
||||
Prefer helpers first. If you need custom SQL for workflow joins, timestamps, or
|
||||
message reactions, read `references/schema.md` before writing the SQL.
|
||||
|
||||
Do not derive workflow counts only from `sessions({ after, before })`: long
|
||||
sessions can start before the period and still contain workflow runs inside the
|
||||
period. Do not scope workflow lookup by exact `project_path`; nested cwd values
|
||||
can belong to the same Claude project slug.
|
||||
|
||||
For each candidate workflow:
|
||||
|
||||
- get the actual workflow_name from `workflows()` or `workflowTree()`;
|
||||
- collect run id, timestamp, project, agent count, and compact result for stats
|
||||
and evidence only;
|
||||
- search the parent session for the user message immediately following the workflow completion;
|
||||
- use that user reaction as `items[].reaction`.
|
||||
|
||||
Rank rows by the strength of the user reaction, not by agent count, workflow
|
||||
size, duration, or implementation importance. A small workflow with "完美" is a
|
||||
better row than a large workflow with no visible response.
|
||||
|
||||
Do not use architecture topics, memory-system milestones, app modules, or recap
|
||||
feature work as workflow rows unless they are actual workflow_name values.
|
||||
Do not make a row for a workflow with no visible user reaction; keep it only in
|
||||
`stats`, `metrics`, or `evidence`.
|
||||
|
||||
Read this card's writing file immediately after workflow evidence is stable:
|
||||
`references/recap/writing4-workflow.md`. Then update the JSON `workflow` card,
|
||||
top-level workflow metrics, and source session ids for workflow evidence.
|
||||
Do not read `pattern5-closing.md` until this JSON update is done.
|
||||
|
||||
Stop when every displayed row has an actual workflow name and a visible user
|
||||
reaction.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Card 5 Closing Retrieval
|
||||
|
||||
Goal: close with a small personal receipt. Use the same period and source scope
|
||||
as the recap, or explicitly record a wider metric in `evidence`.
|
||||
|
||||
Retrieve:
|
||||
|
||||
- one consistent metric that can stand alone, such as streak, active days,
|
||||
sessions, messages, or workflows;
|
||||
- one or two compact receipts;
|
||||
- most said phrase, only if a real repeated user phrase is supported;
|
||||
- signoff material from the period's mood, not a second summary.
|
||||
|
||||
For phrase counts, count only non-meta visible user text. For streaks and active
|
||||
days, define whether the scope is all Obelisk data, the current project, or the
|
||||
selected evidence sessions. Keep the scope consistent with the cover footer
|
||||
unless the evidence explicitly says otherwise.
|
||||
|
||||
Prefer helpers first. If you need custom SQL for phrase counts, active days, or
|
||||
streaks, read `references/schema.md` before writing the SQL.
|
||||
|
||||
Avoid:
|
||||
|
||||
- naked numbers without units;
|
||||
- project report bullets;
|
||||
- internal session names;
|
||||
- token audits;
|
||||
- slogans, advice, or next-action commands.
|
||||
|
||||
Read this card's writing file immediately after the closing receipt is chosen:
|
||||
`references/recap/writing5-closing.md`. Then update the JSON `closing` card and
|
||||
add evidence for counts and phrases.
|
||||
This is the final card; save the completed JSON before replying.
|
||||
|
||||
Stop when the closing can end the deck without explaining the whole week again.
|
||||
@@ -0,0 +1,83 @@
|
||||
# Card 1 Cover Writing
|
||||
|
||||
The cover should be readable in one glance: badge, persona, one plain claim,
|
||||
activity, footer. Before writing, say the claim to the user in a chat bubble.
|
||||
If it sounds like a topic list or report heading, shrink it.
|
||||
|
||||
## Mock taste anchor
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "cover",
|
||||
"badge": "Week 24",
|
||||
"title": "The Architect",
|
||||
"claim": "从零设计了一个完整的 memory 系统。",
|
||||
"activity": [0.85, 0.92, 0.72, 0.45, 0.88, 0.30, 0],
|
||||
"footer": "12 sessions · 2.4M tokens"
|
||||
}
|
||||
```
|
||||
|
||||
This works because `从零设计了一个完整的 memory 系统。` is one plain claim, in
|
||||
the user's language, and can be read in one breath. `The Architect` is English
|
||||
chrome; it gives the card a designed surface without translating the user's
|
||||
actual work.
|
||||
|
||||
## JSON Shape
|
||||
|
||||
```ts
|
||||
type CoverCard = {
|
||||
type: "cover";
|
||||
badge: string;
|
||||
title: string;
|
||||
claim: string;
|
||||
activity: number[];
|
||||
footer: string;
|
||||
evidence_refs?: string[];
|
||||
};
|
||||
```
|
||||
|
||||
Field duties:
|
||||
|
||||
- `badge`: compact period chrome, such as `Week 24`.
|
||||
- `title`: persona label, usually `The Architect`, `The Debugger`, etc.
|
||||
- `claim`: one plain claim; not a topic list, project inventory, colon-led
|
||||
tagline, or clever English that hides the user's language.
|
||||
- `activity`: period intensity values from retrieval.
|
||||
- `footer`: public metric line with no internal filter notes.
|
||||
|
||||
After writing, check that `persona.claim` and `cover.claim` tell the same
|
||||
story, and attach `evidence_refs` to the claim or metric if it is surprisingly
|
||||
specific.
|
||||
|
||||
## First JSON Write
|
||||
|
||||
After Card 1, create or update the recap JSON file. Do this before reading
|
||||
`pattern2-thinking.md`.
|
||||
|
||||
Use this top-level shape:
|
||||
|
||||
```ts
|
||||
type Recap = {
|
||||
schema_version: "obelisk.recap.v1";
|
||||
kind: "weekly" | "monthly";
|
||||
generated_at: string;
|
||||
period: { label: string; start: string; end: string; timezone: string };
|
||||
source: { project?: string; session_ids: string[]; memory_ids?: string[] };
|
||||
metrics: {
|
||||
sessions?: number;
|
||||
messages?: number;
|
||||
tokens?: number;
|
||||
active_days?: number[];
|
||||
streak_days?: number;
|
||||
workflows?: number;
|
||||
workflow_agents?: number;
|
||||
corrections?: number;
|
||||
};
|
||||
persona: { archetype: string; title: string; claim: string; tone: string };
|
||||
cards: [CoverCard, { type: "thinking_path" }, { type: "vibe" }, { type: "workflow" }, { type: "closing" }];
|
||||
evidence?: Array<{ id: string; session_id?: string; message_uuid?: string; memory_id?: string; summary?: string }>;
|
||||
};
|
||||
```
|
||||
|
||||
For app handoff, write JSON under `~/.obelisk/recap/`. Weekly filenames are
|
||||
`recap-{YYYY}-W{WW}.json`; monthly filenames are `recap-{YYYY}-{MM}.json`.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Card 2 Thinking Writing
|
||||
|
||||
Thinking Path should feel like a few bends in the user's reasoning, not a
|
||||
weekly changelog. Before writing, test each row by asking: "what changed here?"
|
||||
|
||||
## Mock taste anchor
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "thinking_path",
|
||||
"title": "Five questions, five turns.",
|
||||
"items": [
|
||||
{ "day": "Mon", "prompt": "为什么要把 session 编译成 wiki?", "turn": "raw SQLite, no wiki" },
|
||||
{ "day": "Tue", "prompt": "buildWhere 是什么", "turn": "unified filter opts, not DSL" },
|
||||
{ "day": "Wed", "prompt": "failures() 90% 误报", "turn": "is_error in JSONL" },
|
||||
{ "day": "Thu", "prompt": "memory 层需要清理机制吗", "turn": "soft-delete, human-only" },
|
||||
{ "day": "Fri", "prompt": "热力图不选中默认显示本月", "turn": "GitHub-style activity timeline" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The prompts stay close to the user's words. Each turn is a short decision
|
||||
fragment, not a full explanation.
|
||||
|
||||
## JSON Shape
|
||||
|
||||
```ts
|
||||
type ThinkingPathCard = {
|
||||
type: "thinking_path";
|
||||
title: string;
|
||||
items: Array<{
|
||||
day: string;
|
||||
prompt: string;
|
||||
turn: string;
|
||||
evidence_refs?: string[];
|
||||
}>;
|
||||
};
|
||||
```
|
||||
|
||||
Field duties:
|
||||
|
||||
- `title`: designed deck line, not `本周路径`, not a research-paper heading.
|
||||
- `prompt`: user's compact question, friction, or task. Use source language.
|
||||
- `turn`: short decision fragment, finding, or shift; usually under 10 words.
|
||||
Compact English fragments are allowed when they work as designed chrome.
|
||||
|
||||
After writing, remove any row whose prompt is a workflow name or whose turn
|
||||
describes implementation rather than changed thinking.
|
||||
Update the JSON now before reading `pattern3-vibe.md`.
|
||||
@@ -0,0 +1,73 @@
|
||||
# Card 3 Vibe Writing
|
||||
|
||||
Vibe is affectionate observation. It should make the user recognize themselves
|
||||
without feeling evaluated. Before writing, remove anything that reads like a
|
||||
correction audit, behavior label, diagnosis, or complaint ledger.
|
||||
|
||||
## Mock taste anchor
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "vibe",
|
||||
"title": "A short character study.",
|
||||
"voice_lines": [
|
||||
{ "label": "catchphrase", "text": "这太丑了", "count": 4 },
|
||||
{ "label": "highest praise", "text": "可以" },
|
||||
{ "label": "late night", "text": "你在干什么", "time": "02:47 AM" }
|
||||
],
|
||||
"meter": {
|
||||
"label": "patience",
|
||||
"value": 0.78,
|
||||
"caption": "saint"
|
||||
},
|
||||
"quote": {
|
||||
"text": "若无必要,勿增实体。",
|
||||
"caption": "your most philosophical moment"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The humor comes from exact small lines. `可以` is funnier and truer than
|
||||
"approval signal".
|
||||
|
||||
## JSON Shape
|
||||
|
||||
```ts
|
||||
type VibeCard = {
|
||||
type: "vibe";
|
||||
title: string;
|
||||
voice_lines: Array<{
|
||||
label: string;
|
||||
text: string;
|
||||
count?: number;
|
||||
time?: string;
|
||||
evidence_refs?: string[];
|
||||
}>;
|
||||
meter?: {
|
||||
label: string;
|
||||
value: number;
|
||||
caption: string;
|
||||
};
|
||||
quote?: {
|
||||
text: string;
|
||||
caption?: string;
|
||||
evidence_refs?: string[];
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Field duties:
|
||||
|
||||
- `title`: light character-study line, not a scorecard.
|
||||
- `voice_lines[].text`: exact user words; no paraphrase, translation,
|
||||
ellipsized half-quote, meta text, or correction log.
|
||||
- `voice_lines[].label`: designed chrome can be English; the quoted user text
|
||||
stays in source language.
|
||||
- `meter`: meter is not a diagnosis. Keep the caption one or two words and
|
||||
affectionate, never punitive.
|
||||
- `quote.text`: one exact user phrase or sentence.
|
||||
|
||||
Do not use `[Request interrupted by user]`, tool output, injected context, or
|
||||
UI status text as vibe. After writing, verify every `voice_lines[].text` and
|
||||
`quote.text` can be traced to a non-meta user message.
|
||||
Update the JSON now before reading `pattern4-workflow.md`.
|
||||
@@ -0,0 +1,68 @@
|
||||
# Card 4 Workflow Writing
|
||||
|
||||
Workflow is the orchestration card. It should show the strongest few workflow
|
||||
runs and the user's reaction to them. Before writing, remove any row whose
|
||||
reaction is not traceable to a visible user reaction.
|
||||
|
||||
## Mock taste anchor
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "workflow",
|
||||
"title": "Three workflows. Forty-two agents.",
|
||||
"deck": "你召唤了机器军团。结果各有不同。",
|
||||
"stats": "3 workflows · 42 agents",
|
||||
"items": [
|
||||
{ "name": "hono-plugin-review", "reaction": "完美" },
|
||||
{ "name": "vue-migration", "reaction": "你这页面完全和之前的不一样…" },
|
||||
{ "name": "split-render-js", "reaction": "可以" }
|
||||
],
|
||||
"verdict": "Mostly tolerated."
|
||||
}
|
||||
```
|
||||
|
||||
The row reactions are user reactions. The title carries the metric; the verdict
|
||||
is a small English seal.
|
||||
|
||||
## JSON Shape
|
||||
|
||||
```ts
|
||||
type WorkflowCard = {
|
||||
type: "workflow";
|
||||
title: string;
|
||||
deck?: string;
|
||||
stats?: string;
|
||||
items: Array<{
|
||||
name: string;
|
||||
reaction: string;
|
||||
evidence_refs?: string[];
|
||||
}>;
|
||||
verdict: string;
|
||||
};
|
||||
```
|
||||
|
||||
Field duties:
|
||||
|
||||
- `title`: human story line or compact metric line.
|
||||
- `deck`: optional second line; do not repeat stats mechanically.
|
||||
- `stats`: compact count line.
|
||||
- `items[].name`: actual workflow name, command name, or run-id prefix.
|
||||
- `items[].reaction`: exact or lightly trimmed user reaction. Preserve source
|
||||
language. No feature description, implementation summary, agent count,
|
||||
duration, "framework switch", "modularization", "theming landed", or other
|
||||
internal progress label.
|
||||
- `verdict`: compact seal based on the row reactions, often 3-6 words.
|
||||
|
||||
Agent counts belong only in `title` or `stats`, never in `items[].reaction`.
|
||||
These row values are invalid because they are implementation labels, not user
|
||||
reactions:
|
||||
|
||||
- `13 agents, the big build` is invalid.
|
||||
- `9 agents, framework switch` is invalid.
|
||||
- `6 agents, modularization` is invalid.
|
||||
- `theming landed` is invalid.
|
||||
|
||||
If no user reaction exists, omit the row rather than write an implementation result.
|
||||
After writing, check that every row name maps to retrieval evidence and every
|
||||
reaction can be read as quoted user verdict text.
|
||||
Update the JSON now before reading `pattern5-closing.md`.
|
||||
@@ -0,0 +1,54 @@
|
||||
# Card 5 Closing Writing
|
||||
|
||||
Closing is a receipt, not a second summary. Before writing, read the headline
|
||||
alone. If it does not mean anything without the rest of the card, add the unit
|
||||
or choose a better line.
|
||||
|
||||
## Mock taste anchor
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "closing",
|
||||
"headline": "19 days",
|
||||
"receipts": ["847 messages exchanged", "12 corrections · 47 approvals"],
|
||||
"most_said_phrase": "好的开始做吧",
|
||||
"signoff": "See you next week."
|
||||
}
|
||||
```
|
||||
|
||||
This works because `19 days` has a unit, the receipts feel like a small receipt,
|
||||
and `See you next week.` is a quiet goodbye instead of a slogan.
|
||||
|
||||
## JSON Shape
|
||||
|
||||
```ts
|
||||
type ClosingCard = {
|
||||
type: "closing";
|
||||
headline: string;
|
||||
receipts: string[];
|
||||
most_said_phrase?: string;
|
||||
signoff: string;
|
||||
evidence_refs?: string[];
|
||||
};
|
||||
```
|
||||
|
||||
Field duties:
|
||||
|
||||
- `headline`: compact stat or phrase with its unit; not a naked number.
|
||||
- `receipts`: at most two `receipts`, compact and personal.
|
||||
- `most_said_phrase`: complete phrase the user actually said, or omit it.
|
||||
- `signoff`: short and earned; quiet goodbye, not advice or a brand slogan.
|
||||
English signoff chrome such as `See you next week.` is allowed.
|
||||
|
||||
After writing, remove internal scope notes from visible fields and put them in
|
||||
`evidence`. The final card should feel like the deck ending, not the report
|
||||
continuing.
|
||||
|
||||
Final save rules:
|
||||
|
||||
- The file contains only the JSON object: no Markdown fence, no prose.
|
||||
- Keep exactly five cards in this order: cover, thinking_path, vibe, workflow,
|
||||
closing.
|
||||
- Keep private SQL, raw tool output, secrets, long paths, and source caveats out
|
||||
of visible card text; put traceability in `evidence`.
|
||||
- After saving, reply briefly with the saved path and important evidence caveats.
|
||||
+56
-2
@@ -89,7 +89,8 @@ CREATE VIRTUAL TABLE messages_fts USING fts5(
|
||||
);
|
||||
```
|
||||
|
||||
Queried via `MATCH` syntax. Rebuilt on each index pass.
|
||||
Queried via `MATCH` syntax. The table is kept in sync by the `messages_fts_*`
|
||||
triggers above; rebuild it manually only when repairing FTS state.
|
||||
|
||||
### memories_fts
|
||||
|
||||
@@ -384,6 +385,31 @@ const msgs = thread('session-uuid');
|
||||
return { count: msgs.length, first: msgs[0]?.text?.slice(0, 100) };
|
||||
```
|
||||
|
||||
#### `raw(uuid, opts?)`
|
||||
|
||||
Windowed access to the original JSONL line for a message. Use this when indexed
|
||||
text, tool inputs, or tool results were truncated and you need the raw source.
|
||||
It resolves main-session, subagent, and workflow-agent JSONL paths from the
|
||||
indexed message metadata.
|
||||
|
||||
| Param | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `uuid` | `string` | Message UUID |
|
||||
| `opts.offset` | `number` | Character offset into the JSONL line (default 0) |
|
||||
| `opts.limit` | `number` | Max characters to return (default 10000) |
|
||||
|
||||
**Returns:** `{ text, totalLength, offset, limit, hasMore }` or `null` if the
|
||||
source line cannot be found.
|
||||
|
||||
```js
|
||||
const line = raw('message-uuid', { offset: 0, limit: 4000 });
|
||||
return {
|
||||
preview: line?.text,
|
||||
has_more: line?.hasMore,
|
||||
total: line?.totalLength,
|
||||
};
|
||||
```
|
||||
|
||||
#### `subagents(opts?)`
|
||||
|
||||
All subagent spawns, with message counts. For backward compatibility, passing a string is treated as `sessionId`.
|
||||
@@ -484,6 +510,34 @@ const last5 = recent(5);
|
||||
return last5.map(s => ({ title: s.title, project: s.project_path, ended: s.ended_at }));
|
||||
```
|
||||
|
||||
#### `summaries(opts?)`
|
||||
|
||||
Session summary rows, newest first. For backward compatibility, passing a
|
||||
string is treated as `sessionId`, and passing a number is treated as `limit`.
|
||||
|
||||
| Param | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `opts.sessionId` | `string` | Restrict to one session |
|
||||
| `opts.sessions` | `string[]` | Restrict to a set of session IDs |
|
||||
| `opts.project` | `string` | SQL `LIKE` pattern over `sessions.project` |
|
||||
| `opts.after` | `string` | ISO 8601 lower bound on summary timestamp |
|
||||
| `opts.before` | `string` | ISO 8601 upper bound on summary timestamp |
|
||||
| `opts.branch` | `string` | Filter by source session git branch (exact match) |
|
||||
| `opts.limit` | `number` | Max results (default 100) |
|
||||
|
||||
**Returns:** `Array<summary_row & { session_title, project }>` ordered by
|
||||
`timestamp` descending.
|
||||
|
||||
```js
|
||||
const rows = summaries({ project: '%quiet-zero%', limit: 5 });
|
||||
return rows.map(s => ({
|
||||
session: s.session_title,
|
||||
source: s.source,
|
||||
summary: s.content?.slice(0, 240),
|
||||
timestamp: s.timestamp,
|
||||
}));
|
||||
```
|
||||
|
||||
#### `overview(opts?)`
|
||||
|
||||
Compact orientation map for choosing the next retrieval scope. It is not an
|
||||
@@ -785,7 +839,7 @@ const wfs = workflows();
|
||||
for (const wf of wfs.slice(0, 3)) {
|
||||
const tree = workflowTree(wf.run_id);
|
||||
wf.agent_details = tree?.agents.map(a => ({
|
||||
type: a.agent_type, desc: a.description, msgs: a.messages.length,
|
||||
type: a.agent_type, desc: a.description, msgs: a.messageCount,
|
||||
}));
|
||||
}
|
||||
return wfs.slice(0, 3);
|
||||
|
||||
Reference in New Issue
Block a user