linersh 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/liner.js +37 -0
- package/cli-update-docs/ABOUT.md +69 -0
- package/cli-update-docs/CURATION.md +261 -0
- package/cli-update-docs/JOB-STORY-MIGRATION.md +99 -0
- package/cli-update-docs/JTBD-MASTER-PROMPT-ABOUT.md +133 -0
- package/cli-update-docs/JTBD-MASTER-PROMPT.md +147 -0
- package/cli-update-docs/MIXTAPE-FORMAT.md +398 -0
- package/cli-update-docs/PLATFORM.md +210 -0
- package/cli-update-docs/README.md +107 -0
- package/cli-update-docs/SKILL.md +244 -0
- package/cli-update-docs/TUI-BACKLOG.md +196 -0
- package/cli-update-docs/curator-notes.md +84 -0
- package/cli-update-docs/quality-check-tests.md +196 -0
- package/cli-update-docs/source-finding-tactics.md +99 -0
- package/cli-update-docs/source-quality-hierarchy.md +130 -0
- package/cli-update-docs/synthesis-guidance.md +133 -0
- package/dist/App.js +29 -12
- package/dist/App.js.map +1 -1
- package/dist/agents/detect.js +14 -4
- package/dist/agents/detect.js.map +1 -1
- package/dist/colors.js +48 -21
- package/dist/colors.js.map +1 -1
- package/dist/components/Header.js +5 -5
- package/dist/components/Header.js.map +1 -1
- package/dist/components/KeyHints.js +9 -2
- package/dist/components/KeyHints.js.map +1 -1
- package/dist/components/LabeledBox.js +2 -2
- package/dist/components/LabeledBox.js.map +1 -1
- package/dist/components/NextSteps.js +2 -2
- package/dist/components/NextSteps.js.map +1 -1
- package/dist/open-folder.js +28 -0
- package/dist/open-folder.js.map +1 -0
- package/dist/screens/AgentSetup.js +12 -12
- package/dist/screens/AgentSetup.js.map +1 -1
- package/dist/screens/BootSplash.js +30 -15
- package/dist/screens/BootSplash.js.map +1 -1
- package/dist/screens/CompileView.js +21 -12
- package/dist/screens/CompileView.js.map +1 -1
- package/dist/screens/FramingConfirmReview.js +6 -6
- package/dist/screens/FramingConfirmReview.js.map +1 -1
- package/dist/screens/Gate1Review.js +4 -4
- package/dist/screens/Gate1Review.js.map +1 -1
- package/dist/screens/Gate2Review.js +4 -4
- package/dist/screens/Gate2Review.js.map +1 -1
- package/dist/screens/ImportPrompt.js +3 -3
- package/dist/screens/ImportPrompt.js.map +1 -1
- package/dist/screens/LocalFilePicker.js +5 -5
- package/dist/screens/LocalFilePicker.js.map +1 -1
- package/dist/screens/NewMixtapeWizard.js +14 -14
- package/dist/screens/NewMixtapeWizard.js.map +1 -1
- package/dist/screens/PhaseRunner.js +52 -43
- package/dist/screens/PhaseRunner.js.map +1 -1
- package/dist/screens/ProcessManifest.js +4 -4
- package/dist/screens/ProcessManifest.js.map +1 -1
- package/dist/screens/ProjectHub.js +31 -25
- package/dist/screens/ProjectHub.js.map +1 -1
- package/dist/screens/SourceModal.js +2 -2
- package/dist/screens/SourceModal.js.map +1 -1
- package/dist/screens/TapeBrowser.js +10 -9
- package/dist/screens/TapeBrowser.js.map +1 -1
- package/dist/screens/TapeDraftReview.js +17 -17
- package/dist/screens/TapeDraftReview.js.map +1 -1
- package/dist/screens/TapeEditor.js +5 -5
- package/dist/screens/TapeEditor.js.map +1 -1
- package/dist/screens/cassette-art.js +21 -21
- package/package.json +5 -4
- package/dist/browser-support.js +0 -62
- package/dist/browser-support.js.map +0 -1
- package/dist/screens/BrowserSetup.js +0 -181
- package/dist/screens/BrowserSetup.js.map +0 -1
- package/dist/screens/NewProjectPrompt.js +0 -66
- package/dist/screens/NewProjectPrompt.js.map +0 -1
- package/dist/screens/Settings.js +0 -72
- package/dist/screens/Settings.js.map +0 -1
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# JTBD Master Prompt
|
|
2
|
+
|
|
3
|
+
A drop-in prompt that interviews a Liner user and emits one tight, hyper-specific Job Story — the kind that belongs in the `jtbd:` field of a `tape.yaml`. Paste it into any AI chat as the opening message, or load it as Phase 1 inside the `curating-mixtapes` skill. Its only output is the Job Story sentence; everything downstream (knowledge map, candidate discovery, evaluation, synthesis) is Liner's job, not this prompt's.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## The prompt
|
|
8
|
+
|
|
9
|
+
Copy everything between the `---BEGIN---` and `---END---` markers.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
---BEGIN---
|
|
13
|
+
You run a focused interview that ends in exactly one sentence: a job-to-be-done (JTBD) statement for the `jtbd:` field of a Liner `tape.yaml`. That sentence drives every downstream Liner decision, so it has to be tight. Your only deliverable is that statement, on its own line.
|
|
14
|
+
|
|
15
|
+
## What "tight" means
|
|
16
|
+
|
|
17
|
+
The form: "When [circumstance], I want [motivation], so I can [outcome]."
|
|
18
|
+
|
|
19
|
+
All three slots are required. The form is permissive on what fills them — a legal Job Story, a clinical Job Story, and an engineering Job Story share this shape but no vocabulary. The form's only structural guarantee is that no slot can be empty; the rubric below catches the rest.
|
|
20
|
+
|
|
21
|
+
Failures to refuse:
|
|
22
|
+
|
|
23
|
+
- "When I'm working in healthcare, I want to do healthcare marketing, so I can grow the business." — All slots filled but each is mush; circumstance and motivation both restate the topic.
|
|
24
|
+
- "When I'm practicing law, I want to be a better lawyer, so I can serve clients well." — Motivation is aspiration, not a concrete job.
|
|
25
|
+
- "When our database hits scale limits, I want to migrate to PostgreSQL using Prisma, so I can ship features faster." — Solution baked into the motivation.
|
|
26
|
+
- "When I'm prepping a class, I want to design a curriculum and teach it, so I can finish the term." — Two motivations joined by "and."
|
|
27
|
+
- "When I'm doing marketing, I want to do it the right way, so I can succeed." — Circumstance, motivation, and outcome are all undefined.
|
|
28
|
+
|
|
29
|
+
## Hard rules
|
|
30
|
+
|
|
31
|
+
- No vendor, framework, library, methodology, or tool name in any slot of the final statement.
|
|
32
|
+
- No "and," comma, or slash joining two circumstances, two motivations, or two outcomes. If the user describes two, ask which one this mixtape is for.
|
|
33
|
+
- A bare noun phrase ("mobile design," "contract law") is not a JTBD. A JTBD has a scoped circumstance, a concrete motivation, and a meaningful outcome.
|
|
34
|
+
- Do not invent context. If you don't know the user's role, platform, deadline, or audience, ask.
|
|
35
|
+
- Do not credentialize ("As an expert JTBD practitioner..."). Name the task instead.
|
|
36
|
+
- Do not narrate, summarize, or restate the conversation.
|
|
37
|
+
- Output the statement alone on its own line. No quotes, code fence, header, or commentary.
|
|
38
|
+
- Hard cap: five questions across the entire interview. Three is typical. If you're about to ask a fourth follow-up, draft instead.
|
|
39
|
+
|
|
40
|
+
## Step 0: Offer to read project material
|
|
41
|
+
|
|
42
|
+
Your first reply is one short question, before any interview questions:
|
|
43
|
+
|
|
44
|
+
> Before we begin, do you have any documents or project material I should look at first? If yes, drop them into this chat (or point me at a folder if I have filesystem access here). If not, just say so and we'll talk it through.
|
|
45
|
+
>
|
|
46
|
+
> A few well-chosen files beat a full dump.
|
|
47
|
+
|
|
48
|
+
This question does not count against the question budget.
|
|
49
|
+
|
|
50
|
+
**If the user shares material:** Read it. Stop when you can name domain, audience, stage, and an explicit goal. Then go to confirmation (below).
|
|
51
|
+
|
|
52
|
+
**If the user has no material to share:** Go straight to the interview protocol.
|
|
53
|
+
|
|
54
|
+
**If the user points at a folder and you have no file tools:** Say so plainly and ask them to drop files into the chat or describe the project. Do not pretend you read something you couldn't.
|
|
55
|
+
|
|
56
|
+
## Confirmation (after reading, if material was shared)
|
|
57
|
+
|
|
58
|
+
One turn, one message:
|
|
59
|
+
|
|
60
|
+
> I see your project is [X] for [Y], focused on [Z]. Is the mixtape meant to help you (a) [candidate], (b) [candidate], (c) [candidate], or (d) something else?
|
|
61
|
+
|
|
62
|
+
Candidates are casual-language scopings, not Job Stories yet — you translate at emit time. `(d)` is required. If the user picks it, ask one descent question and draft.
|
|
63
|
+
|
|
64
|
+
If the user contradicts what you read, the user wins. Probe the contradiction once if it changes the circumstance, motivation, or outcome; otherwise accept and proceed.
|
|
65
|
+
|
|
66
|
+
## Interview protocol
|
|
67
|
+
|
|
68
|
+
Open with a single batched message asking only what you can't infer from material the user shared:
|
|
69
|
+
|
|
70
|
+
1. What domain or topic is this mixtape about?
|
|
71
|
+
2. Who are you in this work — what role or context shapes which sources count as canonical?
|
|
72
|
+
3. What will you actually do with an AI that has this context — one concrete activity, not a vibe?
|
|
73
|
+
|
|
74
|
+
Skip any of those that shared material already answered.
|
|
75
|
+
|
|
76
|
+
After the batch, one question at a time, walking down the scope ladder. The user expresses each level in casual language; you translate the micro level into Job Story form at emit time. Three illustrative fields (substitute the user's actual field):
|
|
77
|
+
|
|
78
|
+
- **Clinical:** "be a great doctor" → "communicate diagnoses well" → "explain new diagnoses to patients" → "explain a new Type 2 diabetes diagnosis to an adult with low health literacy at a first visit."
|
|
79
|
+
- **Engineering:** "ship faster" → "reduce CI runtime" → "speed up the integration test suite" → "speed up the integration test suite for a Rails 7 monolith with 3,200 tests while keeping coverage above 85%."
|
|
80
|
+
- **Creative:** "write better" → "improve my essays" → "structure long-form essays" → "structure 4,000-word tech essays for a developer audience reading on mobile."
|
|
81
|
+
|
|
82
|
+
The corresponding final Job Story for the clinical example would be: "When I deliver a new Type 2 diabetes diagnosis to an adult with low health literacy at a first visit, I want to explain the condition and the immediate care plan, so the patient leaves able to describe what diabetes is and one thing they need to do this week."
|
|
83
|
+
|
|
84
|
+
The JTBD is done when the micro level is single-circumstance, single-scope, concrete enough that a mixtape built against it could be measurably better than no mixtape.
|
|
85
|
+
|
|
86
|
+
**Prefer multi-choice over free-form.** Offer 2–4 candidate scopings in casual language; the user picks or overrides.
|
|
87
|
+
|
|
88
|
+
**Stop when the next question wouldn't change the draft.** After the second descent question, draft silently. Only ask another question if the draft fails the rubric *and* the fix requires user input you don't already have.
|
|
89
|
+
|
|
90
|
+
## Internal rubric (silent)
|
|
91
|
+
|
|
92
|
+
Before emitting, check the draft. If any fail, fix and re-check.
|
|
93
|
+
|
|
94
|
+
1. **Structural.** "When [X], I want [Y], so I can [Z]" — all three slots present and non-empty.
|
|
95
|
+
2. **Solution-free.** No tool, framework, vendor, library, methodology, or specific method named in any slot.
|
|
96
|
+
3. **Single scope.** No "and"/comma/slash joining two circumstances, two motivations, or two outcomes. If a slot decomposes into two complete jobs when split, you had two.
|
|
97
|
+
4. **Specific, not generic or aspirational.** Circumstance is scoped to a real situation, not "when I'm working." Motivation is a concrete action, not "be better at X." Outcome is meaningful, not "so I can succeed."
|
|
98
|
+
5. **Externally readable.** A stranger who has never seen this project could read it and understand what's being asked. Strip "my app," "the team," "our process" unless enough scope makes them legible cold.
|
|
99
|
+
6. **Slot hygiene.** Audience and situational context belong in the circumstance, not the motivation. The motivation describes the action the user is taking; the circumstance describes who it's for and the situation around it. If the draft reads "I want to [action] for [audience]" or "I want to [action] that [explains/serves/teaches] [audience]," move the audience clause into the circumstance and tighten the motivation to the action alone. Sequential clauses in the outcome ("install, then understand, then build") are not a violation — they're one composite outcome.
|
|
100
|
+
|
|
101
|
+
## Emit
|
|
102
|
+
|
|
103
|
+
One line. The Job Story. Alone. No preamble, no "Here's your JTBD," no quotes, no code fence.
|
|
104
|
+
|
|
105
|
+
If the user pushes back, do not defend. Take the correction, re-run the rubric, emit a new statement in the same format.
|
|
106
|
+
---END---
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Why it's shaped this way
|
|
112
|
+
|
|
113
|
+
A few choices that aren't obvious:
|
|
114
|
+
|
|
115
|
+
**Job Story format, not Liner's older house form.** Earlier versions of Liner used "Help me [verb] [object] [scope]." That form was easy to write and matched existing Liner artifacts, but it had no required slots — "Help me with healthcare marketing" looks like the form but isn't a job. The Job Story format ("When [circumstance], I want [motivation], so I can [outcome]") fails structurally when any slot is missing, which raises the floor on what counts as a JTBD before the rubric even runs. This realigns with the recommendation in the mixtape's own synthesis.
|
|
116
|
+
|
|
117
|
+
**The first question is always the context-sharing offer.** This prompt is only ever used for one purpose: to help a user create a fresh JTBD for a Liner mixtape from scratch. Users won't paste pre-drafted JTBDs (the whole point is they don't have one yet) and they may not think to attach material unprompted. The single context-sharing question puts the affordance in front of them once, then gets out of the way. Earlier drafts of this prompt had a longer routing question and multiple "fast paths" for pre-attached material; both turned out to be friction solving for scenarios that don't happen in this prompt's actual deployment.
|
|
118
|
+
|
|
119
|
+
**Slot hygiene as a sixth rubric check.** The other rubric tests catch missing slots, solution leakage, multi-scope jobs, mush, and unreadable references. They miss a recurring quieter failure: audience-scoping camped in the motivation slot. "I want to design a single-page site that explains the tool to people who already use AI" is technically one motivation, but the audience clause ("to people who already use AI") belongs in the circumstance. When audience drifts into the motivation, the circumstance gets thinner and the JTBD reads as less situated than it actually is. The sixth rubric check makes this generalizable rather than per-curator-judgment.
|
|
120
|
+
|
|
121
|
+
**No persona block.** Recent empirical work on persona injection (Zheng et al., 162 personas / 2,410 questions) shows persona prompts don't improve task accuracy on average and that optimal-persona prediction is no better than random. Telling the model "you are an expert JTBD practitioner with twenty years of experience" buys nothing and costs a hedge in the output. The prompt names the task instead.
|
|
122
|
+
|
|
123
|
+
**Failure modes listed before instructions.** Production system prompts shipped by frontier labs read as enumerated lists of mistakes the model used to make. That's the right register here — the prompt's job is to prevent the five specific failure modes (solution-baked-in, conflated jobs, topic-as-JTBD, aspirational mush, death-by-questions) more than it is to teach JTBD theory.
|
|
124
|
+
|
|
125
|
+
**Hard question budget.** Five questions, three typical. The most common interview failure mode is death by clarification — the model keeps asking because "one more question" feels safer than committing. The budget forces a draft.
|
|
126
|
+
|
|
127
|
+
**No rationale or knowledge map in the output.** This prompt has one job: produce the Job Story line. Anything else belongs to the next phase of curation, which Liner already runs.
|
|
128
|
+
|
|
129
|
+
## How to use it
|
|
130
|
+
|
|
131
|
+
The prompt's first move is always the same — ask the user whether they have project material to share, then either read what they hand over or interview them directly. What changes by environment is what counts as "shareable":
|
|
132
|
+
|
|
133
|
+
**Pure chat (Claude.ai, ChatGPT, Cowork web).** Users paste the prompt block (between the BEGIN/END markers) into a fresh chat. They can drop files into the chat when the context-sharing question fires; folder paths aren't viable.
|
|
134
|
+
|
|
135
|
+
**Agent with filesystem access (Claude Code, Cowork desktop, Codex, the Liner TUI as a subprocess).** Both file attachments and folder paths work. If the user gives a path, the agent reads from disk.
|
|
136
|
+
|
|
137
|
+
**Inside the `curating-mixtapes` skill.** Drop the prompt block into `cli-update-docs/SKILL.md` as the body of Phase 1 — Framing, replacing the current paragraph about asking the user for the JTBD. The skill's outer context handles Liner-specific framing; this prompt handles the Job Story elicitation. The skill runs in environments with full filesystem access.
|
|
138
|
+
|
|
139
|
+
**Inside the TUI as a dedicated subprocess.** A `liner jtbd <folder>` command can spawn the agent with the folder path already in context. The agent still asks the context-sharing question — the user might want to add files or skip the folder — but the path is available if they want to use it.
|
|
140
|
+
|
|
141
|
+
## Where it can still go wrong
|
|
142
|
+
|
|
143
|
+
Three known soft spots worth knowing:
|
|
144
|
+
|
|
145
|
+
- **Cooperative-user assumption.** The prompt has no defenses against a user trying to coax a JTBD that legitimizes a harmful product, or against prompt injection from pasted material. If you ever ship this in a context with hostile input, add a refusal clause.
|
|
146
|
+
- **Asymmetric examples by design.** The prompt includes failing Job Story examples but no passing ones. Failing examples teach a rule (the failure mode generalizes the moment you read it); passing examples teach a style and anchor the model on whatever domains they're drawn from. The clinical example in the descent section illustrates *process shape*, not target output shape, which is a weaker anchor — but it's nonzero. If you observe users in adjacent fields pattern-matching on it, swap in two more descent examples from different fields, or strip the example entirely.
|
|
147
|
+
- **Structural and slot-hygiene checks are necessary, not sufficient.** Slot 1 of the rubric only catches *omitted* slots, and slot 6 only catches misplaced audience clauses. They don't catch mush, weak audience scoping, or product-positioning that doesn't earn its slot — those remain curator-level judgments. The qualitative rubric stays load-bearing. The format and the structural checks raise the floor; they don't replace the rubric.
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
# Mixtape Format
|
|
2
|
+
|
|
3
|
+
The technical specification for Liner mixtapes.
|
|
4
|
+
|
|
5
|
+
> **Status:** This specification describes the **v1** format (with v1.1 additions for `local_file` sources and `render: js`) as implemented in the CLI. Additional source types planned for v2 are documented at the end.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
A Liner mixtape is a **folder**, not a single file. The folder contains the recipe, fetched source content, a synthesis, and a master file. Together they form a self-contained artifact ready to share, publish, or paste into an AI conversation.
|
|
12
|
+
|
|
13
|
+
This document specifies:
|
|
14
|
+
|
|
15
|
+
- The project folder structure
|
|
16
|
+
- The `tape.yaml` recipe format
|
|
17
|
+
- The contents of `MIXTAPE.md`, `synthesis.md`, and `sources/*.md`
|
|
18
|
+
- The `working/` folder convention
|
|
19
|
+
- The `.mixtape` export format
|
|
20
|
+
- The versioning policy
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## The project folder
|
|
25
|
+
|
|
26
|
+
Every Liner mixtape is a directory. The directory name is a slug — lowercase, hyphenated, filesystem-safe:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
mobile-design-foundations/
|
|
30
|
+
├── MIXTAPE.md # the consumable artifact
|
|
31
|
+
├── tape.yaml # the recipe
|
|
32
|
+
├── synthesis.md # the curator's distilled understanding
|
|
33
|
+
├── sources/ # extracted content for kept sources
|
|
34
|
+
│ ├── 01-<slug>.md
|
|
35
|
+
│ ├── 02-<slug>.md
|
|
36
|
+
│ └── ...
|
|
37
|
+
├── personal/ # curator's local copies of `local_file` sources (optional)
|
|
38
|
+
│ ├── chapter-3.pdf
|
|
39
|
+
│ └── reader-mode-saved-article.md
|
|
40
|
+
└── working/ # the methodology made visible
|
|
41
|
+
├── 01-jtbd-and-knowledge-map.md
|
|
42
|
+
├── 02-candidate-longlist.md
|
|
43
|
+
├── 03-evaluation.yaml
|
|
44
|
+
├── 04-quality-checks.md
|
|
45
|
+
└── 05-empirical-test.md
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The folder is the canonical unit. Any operation that reads or writes a mixtape works on a folder, not on individual files.
|
|
49
|
+
|
|
50
|
+
A minimal valid project folder contains `tape.yaml`, `synthesis.md`, `MIXTAPE.md`, and a `sources/` directory with at least one file. The `working/` folder is recommended but not required. The `personal/` folder exists only when the recipe references at least one `local_file` source.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## `tape.yaml` — the recipe
|
|
55
|
+
|
|
56
|
+
The recipe lists the kept sources with curator notes, organized by section. It is the input to `liner compile`, which produces `MIXTAPE.md` and populates `sources/`.
|
|
57
|
+
|
|
58
|
+
### Required top-level fields
|
|
59
|
+
|
|
60
|
+
| Field | Type | Description |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `title` | string | Display name of the mixtape |
|
|
63
|
+
| `description` | string | One-sentence description of the mixtape's purpose |
|
|
64
|
+
| `curator` | string | Name of the curator |
|
|
65
|
+
| `version` | integer | Tape format version. Must be `1` for v1 format |
|
|
66
|
+
| `mode` | string | `quick` or `methodology` — how this mixtape was curated |
|
|
67
|
+
| `sources` | list | At least one source entry |
|
|
68
|
+
|
|
69
|
+
### Optional top-level fields
|
|
70
|
+
|
|
71
|
+
| Field | Type | Description |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| `tags` | list of strings | Tags for discovery and filtering |
|
|
74
|
+
| `created` | ISO date | Creation date |
|
|
75
|
+
| `updated` | ISO date | Last meaningful update |
|
|
76
|
+
| `license` | string | License identifier (e.g., `CC-BY-4.0`, `MIT`) |
|
|
77
|
+
| `homepage` | URL | Link to the mixtape's home (e.g., its GitHub page) |
|
|
78
|
+
| `jtbd` | string | The job-to-be-done statement in Job Story form: `When [circumstance], I want [motivation], so I can [outcome].` All three slots required. No solution names (vendor, framework, library, methodology, tool) in any slot. One job per slot — no "and"/comma/slash conjunctions. See [`CURATION.md`](CURATION.md) Phase 1 and [`JTBD-MASTER-PROMPT.md`](JTBD-MASTER-PROMPT.md) for the full rubric. |
|
|
79
|
+
| `methodology_version` | string | Which version of CURATION.md was applied |
|
|
80
|
+
|
|
81
|
+
### Source entries
|
|
82
|
+
|
|
83
|
+
v1 supports three source types: `youtube`, `web`, and `local_file`.
|
|
84
|
+
|
|
85
|
+
**Required fields per source:**
|
|
86
|
+
|
|
87
|
+
| Field | Type | Description |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `type` | string | One of `youtube`, `web`, `local_file` |
|
|
90
|
+
| `url` | URL | Required for `youtube` and `web` source types. Omitted for `local_file` |
|
|
91
|
+
| `path` | string | Required for `local_file`. Relative path under `personal/` (e.g., `personal/foo.pdf`) |
|
|
92
|
+
| `citation` | string | Required for `local_file`. Human-readable provenance: author, title, publication, date |
|
|
93
|
+
|
|
94
|
+
**Optional fields per source (all types):**
|
|
95
|
+
|
|
96
|
+
| Field | Type | Description |
|
|
97
|
+
|---|---|---|
|
|
98
|
+
| `note` | string | Curator note. Strongly recommended; required for library contributions |
|
|
99
|
+
| `section` | string | Section label for grouping sources in the compiled mixtape |
|
|
100
|
+
| `priority` | string | `required` (default) or `optional`. Optional sources can be excluded with `--skip-optional` |
|
|
101
|
+
|
|
102
|
+
**Optional fields specific to `web` sources:**
|
|
103
|
+
|
|
104
|
+
| Field | Type | Description |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| `render` | string | Controls how the page is fetched. **Absent (default)** — try server-rendered HTML first; if the page turns out to be JavaScript-only, automatically fall back to headless Chromium (requires `liner setup-js` to have been run). **`js`** — skip the server attempt and go straight to Chromium. **`server`** — server-rendered only; fail loudly on a JS stub. Use `server` for library submissions where you want the recipe to declare no hidden Playwright dependency. |
|
|
107
|
+
|
|
108
|
+
**Optional fields specific to `local_file` sources:**
|
|
109
|
+
|
|
110
|
+
| Field | Type | Description |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| (none yet) | | The required `path` and `citation` cover v1.1 |
|
|
113
|
+
|
|
114
|
+
`local_file` sources can reference content the curator has on disk — book chapters, gated articles, exported PDFs, Reader-Mode-saved HTML. The `path` must resolve under the project's `personal/` subdirectory; absolute paths and `..` traversal are rejected at validation. Supported extensions are `.md`, `.txt`, `.html`, `.htm`, `.pdf`. The maximum file size is 10MB.
|
|
115
|
+
|
|
116
|
+
### Example
|
|
117
|
+
|
|
118
|
+
```yaml
|
|
119
|
+
title: Mobile Design Foundations
|
|
120
|
+
description: Core principles for native mobile UX.
|
|
121
|
+
curator: Your Name
|
|
122
|
+
version: 1
|
|
123
|
+
mode: methodology
|
|
124
|
+
tags: [mobile, design, ux]
|
|
125
|
+
created: 2026-05-18
|
|
126
|
+
license: CC-BY-4.0
|
|
127
|
+
jtbd: When I'm designing the core UI of a consumer iOS app, I want to follow Apple's interaction conventions while choosing where to deviate visually, so I can ship something that feels native without looking generic.
|
|
128
|
+
methodology_version: "2.0"
|
|
129
|
+
|
|
130
|
+
sources:
|
|
131
|
+
- type: web
|
|
132
|
+
url: https://developer.apple.com/design/human-interface-guidelines/gestures
|
|
133
|
+
note: |
|
|
134
|
+
Apple's canonical gesture reference. Skim the overview;
|
|
135
|
+
the per-gesture detail is what matters.
|
|
136
|
+
section: foundations
|
|
137
|
+
|
|
138
|
+
- type: youtube
|
|
139
|
+
url: https://www.youtube.com/watch?v=XXXX
|
|
140
|
+
note: |
|
|
141
|
+
Watch first. The section starting at 14:30 on touch
|
|
142
|
+
target hierarchy is the load-bearing point.
|
|
143
|
+
section: foundations
|
|
144
|
+
|
|
145
|
+
- type: web
|
|
146
|
+
url: https://example.com/article-on-mobile-nav
|
|
147
|
+
note: |
|
|
148
|
+
Critique of bottom-tab navigation patterns. Take with
|
|
149
|
+
the next source which disagrees.
|
|
150
|
+
section: patterns
|
|
151
|
+
|
|
152
|
+
- type: web
|
|
153
|
+
url: https://example.com/counterargument
|
|
154
|
+
note: Defends bottom tabs for high-frequency apps.
|
|
155
|
+
section: patterns
|
|
156
|
+
priority: optional
|
|
157
|
+
|
|
158
|
+
- type: web
|
|
159
|
+
url: https://developer.apple.com/design/human-interface-guidelines/accessibility
|
|
160
|
+
render: js
|
|
161
|
+
note: Requires headless-browser rendering; install `linersh[js]` first.
|
|
162
|
+
section: foundations
|
|
163
|
+
|
|
164
|
+
- type: local_file
|
|
165
|
+
path: personal/touch-target-paper.pdf
|
|
166
|
+
citation: "Parhi et al., 'Target Size for One-Handed Thumb Use on Small Touchscreen Devices,' Mobile HCI 2006."
|
|
167
|
+
note: The canonical empirical study behind Apple's 44pt minimum.
|
|
168
|
+
section: craft
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Validation rules
|
|
172
|
+
|
|
173
|
+
A `tape.yaml` is valid if and only if:
|
|
174
|
+
|
|
175
|
+
1. The YAML parses
|
|
176
|
+
2. All required top-level fields are present
|
|
177
|
+
3. `version` is `1` (v1 parsers reject other values)
|
|
178
|
+
4. `mode` is `quick` or `methodology`
|
|
179
|
+
5. `sources` is a non-empty list
|
|
180
|
+
6. Every source has a `type` in the allowed set: `youtube`, `web`, `local_file`
|
|
181
|
+
7. For `youtube` and `web` sources: `url` is present and parses as a valid URL
|
|
182
|
+
8. For `web` sources: if `render` is present, it is `server` or `js`
|
|
183
|
+
9. For `local_file` sources: `path` and `citation` are present
|
|
184
|
+
10. For `local_file` sources: `path` is a relative POSIX path starting with `personal/` and contains no `..` segments
|
|
185
|
+
11. For `local_file` sources: the extension is one of `.md`, `.txt`, `.html`, `.htm`, `.pdf`
|
|
186
|
+
12. `youtube` and `web` sources must not declare `path` or `citation`; `local_file` sources must not declare `url`
|
|
187
|
+
|
|
188
|
+
Path existence and file-size limits are checked at compile time, not validation time — a tape can be valid even when the file isn't on disk yet (e.g., shared recipe before the recipient adds their own copy).
|
|
189
|
+
|
|
190
|
+
Validation errors should point to the specific field and the specific problem.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## `synthesis.md`
|
|
195
|
+
|
|
196
|
+
The synthesis is the curator's distilled understanding of the domain, expressed in their own voice. It is required — every mixtape has one.
|
|
197
|
+
|
|
198
|
+
The synthesis covers:
|
|
199
|
+
|
|
200
|
+
- The principles or framework the curator sees in the domain
|
|
201
|
+
- Contested questions and where the curator stands
|
|
202
|
+
- Distinctions between concepts that get confused
|
|
203
|
+
- When to use what's in the mixtape and when to look elsewhere
|
|
204
|
+
|
|
205
|
+
Length is typically 800–2000 words. Shorter for narrow topics; longer for broader ones.
|
|
206
|
+
|
|
207
|
+
In quick mode, the synthesis is AI-drafted during compilation. In methodology mode, the curator writes or substantially edits it. Either way, it lives at `synthesis.md` in the project folder and gets included verbatim at the top of `MIXTAPE.md`.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## `MIXTAPE.md` — the master file
|
|
212
|
+
|
|
213
|
+
`MIXTAPE.md` is what the consuming AI actually reads. It is produced by `liner compile` and combines the synthesis with a source index.
|
|
214
|
+
|
|
215
|
+
Structure:
|
|
216
|
+
|
|
217
|
+
```markdown
|
|
218
|
+
# {title}
|
|
219
|
+
|
|
220
|
+
> {description}
|
|
221
|
+
|
|
222
|
+
**Curator:** {curator}
|
|
223
|
+
**Compiled:** {ISO timestamp}
|
|
224
|
+
**Sources:** {n}
|
|
225
|
+
**JTBD:** {jtbd if present}
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## How to use this mixtape
|
|
230
|
+
|
|
231
|
+
[Standard boilerplate explaining that this is a curated context
|
|
232
|
+
bundle, that the synthesis below provides framing, and that
|
|
233
|
+
individual source files are referenced in the index and should
|
|
234
|
+
be consulted when specific detail is needed.]
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Synthesis
|
|
239
|
+
|
|
240
|
+
{contents of synthesis.md, verbatim}
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Sources
|
|
245
|
+
|
|
246
|
+
{for each section, in order of first appearance:}
|
|
247
|
+
|
|
248
|
+
### {section name}
|
|
249
|
+
|
|
250
|
+
#### Source {N}: {source title or citation}
|
|
251
|
+
|
|
252
|
+
- **Type:** {youtube|web|local_file}
|
|
253
|
+
- **URL:** {source url} *(for youtube/web)*
|
|
254
|
+
- **Citation:** {citation} *(for local_file)*
|
|
255
|
+
- **Local path:** {path} *(for local_file)*
|
|
256
|
+
- **Render:** {server|js} *(for web sources, only when explicitly set)*
|
|
257
|
+
- **Author:** {author if known}
|
|
258
|
+
- **Published:** {date if known}
|
|
259
|
+
- **Curator note:** {note}
|
|
260
|
+
- **Content file:** [sources/{nn}-{slug}.md](./sources/{nn}-{slug}.md)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
The "How to use this mixtape" section is standard boilerplate. It tells the consuming AI that the synthesis carries the curator's framing, that source content lives in referenced files, and that the AI should load sources on demand when conversation requires specific detail.
|
|
264
|
+
|
|
265
|
+
The source index entries contain enough metadata for the consuming AI to decide whether to load each source's full content. Curator notes are load-bearing for this routing decision — they're the signal that tells the AI which sources matter for which questions.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## `sources/`
|
|
270
|
+
|
|
271
|
+
The `sources/` folder contains extracted text for every kept source, one file per source, named `01-<slug>.md` through `nn-<slug>.md`. Numbers match the source's position in the compiled mixtape; slugs come from the source's title.
|
|
272
|
+
|
|
273
|
+
Each source file contains:
|
|
274
|
+
|
|
275
|
+
```markdown
|
|
276
|
+
# {source title or citation}
|
|
277
|
+
|
|
278
|
+
**Source type:** {youtube|web|local_file}
|
|
279
|
+
**URL:** {url} *(for youtube/web)*
|
|
280
|
+
**Citation:** {citation} *(for local_file)*
|
|
281
|
+
**Local path:** {path} *(for local_file)*
|
|
282
|
+
**Author:** {author if known}
|
|
283
|
+
**Published:** {date if known}
|
|
284
|
+
**Fetched:** {ISO timestamp}
|
|
285
|
+
|
|
286
|
+
{extracted content}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
For YouTube sources, the extracted content is the transcript, cleaned and joined into paragraphs. For web sources, it's the article text extracted via readability tools, stripped of navigation and boilerplate. For `local_file` sources, the content is extracted by type: `.md`/`.txt` files are read as-is; `.html` is extracted via the same readability pipeline as web sources; `.pdf` is extracted page-by-page via pdfplumber.
|
|
290
|
+
|
|
291
|
+
Source content is stored at full extracted length. The master file pattern handles in-context efficiency by referencing sources on demand rather than embedding them in `MIXTAPE.md`.
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## `working/` — the methodology made visible
|
|
296
|
+
|
|
297
|
+
The `working/` folder contains the curator's research artifacts: the JTBD statement, the knowledge map, the candidate long-list, the evaluation pass with decisions and ratings, and the empirical test result if performed.
|
|
298
|
+
|
|
299
|
+
Files are numbered to indicate phase order:
|
|
300
|
+
|
|
301
|
+
```
|
|
302
|
+
working/
|
|
303
|
+
├── 01-jtbd-and-knowledge-map.md
|
|
304
|
+
├── 02-candidate-longlist.md
|
|
305
|
+
├── 03-evaluation.yaml
|
|
306
|
+
├── 04-quality-checks.md
|
|
307
|
+
└── 05-empirical-test.md
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
These are not required by the format but are recommended. Library contributions must include them.
|
|
311
|
+
|
|
312
|
+
The evaluation file (`03-evaluation.yaml`) is structured — it lists every candidate source with the decision (kept, dropped, deferred) and the rationale. This is distinct from the cache (which holds source *content*); the evaluation file holds *decisions about* sources.
|
|
313
|
+
|
|
314
|
+
Example `03-evaluation.yaml`:
|
|
315
|
+
|
|
316
|
+
```yaml
|
|
317
|
+
candidates:
|
|
318
|
+
- url: https://example.com/great-article
|
|
319
|
+
decision: kept
|
|
320
|
+
section: foundations
|
|
321
|
+
rationale: Canonical reference for the foundations section.
|
|
322
|
+
rating: 5
|
|
323
|
+
- url: https://example.com/listicle
|
|
324
|
+
decision: dropped
|
|
325
|
+
rationale: Shallow listicle, duplicates content in Source 3.
|
|
326
|
+
rating: 1
|
|
327
|
+
- url: https://example.com/contested
|
|
328
|
+
decision: kept
|
|
329
|
+
section: patterns
|
|
330
|
+
rationale: Strong perspective; paired with Source 5 which disagrees.
|
|
331
|
+
rating: 4
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## The content cache
|
|
337
|
+
|
|
338
|
+
Source content fetched during research is stored in the curator's local cache, not in the project folder. The cache lives at `~/.liner/cache/` (or wherever `platformdirs` puts it on the user's OS).
|
|
339
|
+
|
|
340
|
+
The cache is shared across all the curator's projects. A source fetched for one mixtape is available for all future mixtapes.
|
|
341
|
+
|
|
342
|
+
When `liner compile` runs, it copies the cached content for kept sources into `sources/` in the project folder. The cache itself is not part of the mixtape and is not included in exports.
|
|
343
|
+
|
|
344
|
+
See [PLATFORM.md](./PLATFORM.md) for the cache's role in the broader architecture.
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## The `.mixtape` export format
|
|
349
|
+
|
|
350
|
+
A `.mixtape` file is a zip archive of a project folder, produced by `liner share` and consumed by `liner import`.
|
|
351
|
+
|
|
352
|
+
The archive contains the project folder at its root: `MIXTAPE.md`, `tape.yaml`, `synthesis.md`, `sources/`, `working/`, and `personal/` (when present). The archive does not contain anything from the shared content cache.
|
|
353
|
+
|
|
354
|
+
On import, the receiving Liner unzips the folder, then refetches any sources whose URLs aren't already in the receiving curator's cache. Sources already cached are reused. `local_file` sources are read from the archived `personal/` directly — no refetch.
|
|
355
|
+
|
|
356
|
+
Flags affecting the export:
|
|
357
|
+
|
|
358
|
+
- `--no-working-notes`: exclude `working/` from the archive
|
|
359
|
+
- `--no-personal`: exclude `personal/` from the archive. Used when the curator considers the local copies private (gated content, licensed material) or is preparing a library submission.
|
|
360
|
+
- `--no-source-content`: exclude `sources/` from the archive. The recipient must re-fetch on first compile.
|
|
361
|
+
- `--minimal`: include only `tape.yaml`. The recipient compiles from scratch — and must supply their own local files for any `local_file` sources.
|
|
362
|
+
|
|
363
|
+
**Library contributions** must use `--no-personal` *and* must not contain any `local_file` sources in `tape.yaml`. The library accepts only mixtapes built from publicly fetchable sources.
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Versioning policy
|
|
368
|
+
|
|
369
|
+
The mixtape format has its own version number, independent of the CLI/TUI version.
|
|
370
|
+
|
|
371
|
+
- **v1** is the current format. Stable.
|
|
372
|
+
- **v1.1 additions** (additive, non-breaking): the `local_file` source type, the `render` field on `web` sources, and the `personal/` subdirectory. v1 parsers that don't know about these will reject tapes that use them — they're not silently forward-compatible. v1.1-aware parsers accept everything older v1 parsers accept.
|
|
373
|
+
- Breaking changes increment the format version. v1 mixtapes will continue to parse with v1 tools indefinitely. v2 tools will accept both v1 and v2 mixtapes for some transition period, with a documented migration path.
|
|
374
|
+
- Additive, non-breaking changes (new optional fields, new source types) may happen within a major version with a minor version note.
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## v2 — Planned additions (not yet implemented)
|
|
379
|
+
|
|
380
|
+
The following source types and fields are designed but not yet implemented. Full specifications will land when the implementations do.
|
|
381
|
+
|
|
382
|
+
### Additional source types
|
|
383
|
+
|
|
384
|
+
- `gated_url` — content behind a paywall or login the curator has access to. References the original URL for provenance; requires a `content_file` pointing at a local copy.
|
|
385
|
+
- `pasted` — short content entered directly into `tape.yaml`.
|
|
386
|
+
- `local_media` — audio or video files. Requires external transcription before use.
|
|
387
|
+
|
|
388
|
+
### Additional fields
|
|
389
|
+
|
|
390
|
+
- `content` (for `pasted` sources) — the literal content as a multi-line string.
|
|
391
|
+
- `content_file` (for `gated_url`) — path under `personal/` to a local file containing the saved content.
|
|
392
|
+
- `path` (for `local_media`) — path under `personal/` to the media file.
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## License
|
|
397
|
+
|
|
398
|
+
This specification is part of the Liner project and is MIT-licensed.
|