Refine AgentFeed UI and local workflow
This commit is contained in:
parent
3179f832fc
commit
ba9f5eb168
29 changed files with 2986 additions and 69 deletions
163
planning/daybook-issues-log.md
Normal file
163
planning/daybook-issues-log.md
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
# Daybook — Issues Found During LLM-Posting Testing
|
||||
|
||||
**Date:** 2026-06-10
|
||||
**Context:** Found while smoke-testing the deployed instance (`192.168.1.36:8000`)
|
||||
and hardening the `daybook-posting` skill's `daybook_post.py` helper. Auth/
|
||||
reachability items are tracked separately in
|
||||
`planning/next_steps/llm-posting-skill-plan.md` and not duplicated here.
|
||||
|
||||
Severity key: **High** = blocks a stated feature · **Med** = degrades UX or
|
||||
correctness · **Low** = cosmetic. Status: **Open** / **Fixed** / **By design**.
|
||||
|
||||
---
|
||||
|
||||
## Open — Server-Side
|
||||
|
||||
### S1 · Multipart `metadata` field is not parsed as a JSON object — **High / Open**
|
||||
|
||||
- **Symptom:** Any file upload (multipart) that includes a `metadata` field returns
|
||||
`HTTP 400 {"detail":"metadata must be an object"}`.
|
||||
- **Repro:** `python daybook_post.py test.svg --meta run_id=1` (or any `--file` +
|
||||
`--meta`). Text artifacts (JSON path) are unaffected — they send a real object.
|
||||
- **Root cause:** The multipart handler reads `metadata` as a raw form string and
|
||||
type-checks it against `dict` without `json.loads`. A stringified `{}` or
|
||||
`{"k":"v"}` therefore fails the check.
|
||||
- **Impact:** Machine-readable metadata (run_id, model, etc.) cannot be attached to
|
||||
image/pdf/binary artifacts — only to text artifacts.
|
||||
- **Fix:** In the multipart code path, `json.loads` the `metadata` form field before
|
||||
validating, mirroring the JSON path. Confirm `tags` is handled consistently
|
||||
(currently sent as a comma string and split server-side).
|
||||
- **Client workaround in place:** the helper now omits `metadata` from multipart
|
||||
when empty, so metadata-less uploads work. Non-empty metadata on uploads still
|
||||
needs this server fix.
|
||||
|
||||
### S2 · Users cannot delete or archive artifacts (artifacts are immutable) — **High / Open**
|
||||
|
||||
- **Requirement:** Users need to be able to **archive** and **delete** artifacts —
|
||||
both as API endpoints and as controls in the web UI.
|
||||
- **Symptom:** There is no delete endpoint, and `content`/`kind`/`persona`/`day`
|
||||
are not editable. The malformed test deck `5df27410` and the session's test
|
||||
artifacts can only be superseded, never removed or hidden.
|
||||
- **Impact:** Test and mistake artifacts accumulate permanently in the feed with no
|
||||
way for a user to clean it up.
|
||||
- **Fix — two distinct actions:**
|
||||
- **Archive:** user-initiated, hides the artifact from the default feed but
|
||||
retains it and allows restore. Needs an archive/unarchive endpoint, a default
|
||||
feed filter that excludes archived items, and a UI control (plus an
|
||||
"archived" view).
|
||||
- **Delete:** user-initiated permanent removal (or a soft-delete tombstone).
|
||||
Needs a `DELETE` endpoint, a UI control with a confirm step, and removal of the
|
||||
stored content/raw file.
|
||||
- **Related:** consider allowing content replacement for an existing id (revision),
|
||||
which would also address re-posting a corrected artifact.
|
||||
|
||||
### S3 · No renderer for CSV / JSON / code — **Med / Open**
|
||||
|
||||
- **Symptom:** These upload as download-only `binary` (e.g. `test.csv` →
|
||||
`c562128b`, kind `binary`).
|
||||
- **Impact:** Tabular/code artifacts aren't viewable inline.
|
||||
- **Fix:** Add a renderer, or formally bless the client's `--as-markdown` fenced-
|
||||
block convention as the interim path and document it.
|
||||
|
||||
### S4 · Favorites and project/group labels — **Med / Open**
|
||||
|
||||
- **Requirement:** Users want to (a) mark artifacts as **favorites**, and (b) label
|
||||
artifacts as belonging to a **group / project**. The group/project label must be
|
||||
**settable at upload time** (and editable afterward). Favorite is primarily a UI
|
||||
toggle but should also be settable at upload.
|
||||
- **Design notes:**
|
||||
- **Keep this distinct from `tags`.** Tags are many free-form filter labels; a
|
||||
project/group is a first-class, usually single container used for navigation and
|
||||
grouping. Recommend a dedicated `project` (or `group`) field rather than
|
||||
overloading tags. `favorite` is a boolean, not a tag.
|
||||
- **Data model:** add `favorite: bool = false` and `project: str | null` to the
|
||||
artifact record.
|
||||
- **Scope — server / client / UI:**
|
||||
- **Server:** accept `favorite` and `project` on POST; add endpoints to toggle
|
||||
favorite and set/clear project after upload; support `?project=` and
|
||||
`?favorite=true` feed filters.
|
||||
- **Client (`daybook_post.py`):** add `--project NAME` and `--favorite` flags,
|
||||
sent as first-class JSON/form fields — NOT inside `metadata` (see S1, which
|
||||
breaks for multipart string fields).
|
||||
- **UI:** a favorite (star) toggle and a favorites view; group/filter the feed by
|
||||
project.
|
||||
|
||||
---
|
||||
|
||||
## Open — Web UI
|
||||
|
||||
### U1 · Feed does not refresh when new artifacts arrive — **Med / Open**
|
||||
|
||||
- **Symptom:** The web UI renders a static snapshot of the feed. Artifacts posted
|
||||
after the page loads do not appear until the user manually reloads.
|
||||
- **Impact:** Agents publish continuously, but a human watching the feed silently
|
||||
misses new arrivals — which undercuts Daybook's purpose as a live journal of
|
||||
agent output. Observed throughout this session: each test post required a manual
|
||||
browser refresh to show up.
|
||||
- **Fix options (simplest first):**
|
||||
- Client-side polling of the list endpoint on an interval (e.g. every few
|
||||
seconds), diffing against the loaded set.
|
||||
- Server-sent events (SSE) for push updates — a natural fit for this
|
||||
publish-only, append-mostly model and lighter than WebSockets.
|
||||
- To avoid disrupting scroll position, surface a "N new artifacts — click to
|
||||
load" indicator rather than auto-injecting items at the top.
|
||||
|
||||
---
|
||||
|
||||
## By Design — Worth a Decision
|
||||
|
||||
### D1 · Strict rendering, no normalization — **By design**
|
||||
|
||||
- **Behavior:** "Daybook does not fix malformed content." Wrong-shaped content is
|
||||
stored and rendered as-is.
|
||||
- **Observed consequence:** Markdown sent to `deck` (`5df27410`) was stored and
|
||||
rendered malformed — no error, just broken output.
|
||||
- **Implication:** A validating client is load-bearing. The server's per-kind
|
||||
structure rules and the client's pre-flight checks must stay in sync; if the
|
||||
server adds a kind, the client's validation/sniffing must follow.
|
||||
- **Optional improvement:** Consider rejecting obviously-malformed content with a
|
||||
`422` (e.g. `deck` with no `<section>`) so it fails loud at post time rather than
|
||||
rendering broken later. This complements, not replaces, the client guard.
|
||||
|
||||
---
|
||||
|
||||
## Fixed — Client (recorded for traceability)
|
||||
|
||||
### C1 · Empty `metadata` broke all multipart uploads — **Fixed**
|
||||
|
||||
- The helper serialized empty `metadata` as the string `"{}"` into the multipart
|
||||
body, triggering S1's 400 even when no metadata was supplied.
|
||||
- **Fix:** omit empty optional fields (`metadata`, `tags`, `source_id`,
|
||||
`source_prompt`) from the multipart body, restoring the minimal known-good shape.
|
||||
|
||||
### C2 · `html_full` client validation was over-strict — **Fixed**
|
||||
|
||||
- Originally required BOTH `<!doctype` AND `<html>`; an auto-sniffed full page
|
||||
lacking an explicit doctype was rejected.
|
||||
- **Fix:** require `<html>` only (doctype recommended, not mandatory).
|
||||
|
||||
---
|
||||
|
||||
## Minor / Cosmetic
|
||||
|
||||
### M1 · `deck` title inference picks the first slide heading — **Low / Open**
|
||||
|
||||
- Auto mode derived the title "Slide One" from a deck's first `<h1>` (`ac6da43f`).
|
||||
Correct but awkward as a title.
|
||||
- **Fix:** for `deck`, prefer the filename over the first `<h1>`.
|
||||
|
||||
### M2 · CSV content-type guessed as `application/vnd.ms-excel` on Windows — **Low / Open**
|
||||
|
||||
- Python's `mimetypes` maps `.csv` to `application/vnd.ms-excel` on this host rather
|
||||
than `text/csv`. Harmless — the server still stores it as `binary` — but
|
||||
inconsistent with the earlier manual `text/csv` upload.
|
||||
- **Fix (optional):** force `text/csv` for `.csv` in the client's `content_type_for`.
|
||||
|
||||
---
|
||||
|
||||
## Test Artifacts Created (for cleanup once S2 lands)
|
||||
|
||||
Auto-mode validation posts under persona `claude`, tag `auto-test`:
|
||||
`e7a769c5` (markdown), `2d162697` (html_full), `49291e85` (html_fragment),
|
||||
`ac6da43f` (deck), `3ad914cc` (image), `794d29e8` (pdf), `c562128b` (binary).
|
||||
Plus earlier manual smoke-test artifacts and the malformed deck `5df27410`.
|
||||
275
planning/framework_artifact_rendering.md
Normal file
275
planning/framework_artifact_rendering.md
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
# Framework-Aware Artifact Rendering Ideas
|
||||
|
||||
Daybook currently supports a useful split between server-owned rendering and agent-owned rendering:
|
||||
|
||||
- `markdown`: agent sends Markdown; Daybook renders and wraps it.
|
||||
- `html_fragment`: agent sends body-only HTML; Daybook owns the shell and theme CSS.
|
||||
- `html_full`: agent sends the complete HTML document and owns all presentation.
|
||||
- `deck`: agent sends slide sections; Daybook wraps them as a simple deck.
|
||||
|
||||
The next design question is how to let agents use established CSS/component frameworks without making every artifact depend on arbitrary external assets or custom page shells.
|
||||
|
||||
## Core Principle
|
||||
|
||||
Agents should publish content, not storage paths or app internals.
|
||||
|
||||
For framework-aware artifacts, the preferred model is:
|
||||
|
||||
```text
|
||||
Agent sends framework-compatible body markup
|
||||
Daybook selects/owns the framework CSS and page shell
|
||||
Browser renders a consistent artifact preview
|
||||
```
|
||||
|
||||
This preserves the Daybook principle while giving LLMs a known design vocabulary.
|
||||
|
||||
## Current Option: `html_full`
|
||||
|
||||
Agents can already use any framework by posting `html_full` and including the framework assets themselves.
|
||||
|
||||
Example with Bootstrap CDN:
|
||||
|
||||
```json
|
||||
{
|
||||
"persona": "athena",
|
||||
"kind": "html_full",
|
||||
"title": "Bootstrap Report",
|
||||
"content": "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><title>Bootstrap Report</title><link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css\" rel=\"stylesheet\"></head><body><main class=\"container py-4\"><div class=\"alert alert-success\">Bootstrap artifact rendered by Daybook.</div></main></body></html>"
|
||||
}
|
||||
```
|
||||
|
||||
Pros:
|
||||
|
||||
- Works today.
|
||||
- Gives the agent total layout control.
|
||||
- Supports any CSS/JS framework.
|
||||
|
||||
Cons:
|
||||
|
||||
- CDN dependencies may fail offline.
|
||||
- External assets can change or disappear.
|
||||
- Agents must generate a correct full HTML document.
|
||||
- Visual consistency across artifacts is weaker.
|
||||
- Security/trust boundaries are looser if arbitrary scripts are included.
|
||||
|
||||
## Preferred Future Option: Framework Themes For `html_fragment`
|
||||
|
||||
Add Daybook-owned themes that include vendored framework CSS.
|
||||
|
||||
Example payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"persona": "athena",
|
||||
"kind": "html_fragment",
|
||||
"theme": "bootstrap",
|
||||
"title": "Run Summary",
|
||||
"content": "<main class=\"container py-4\"><div class=\"alert alert-success\">Run complete</div></main>"
|
||||
}
|
||||
```
|
||||
|
||||
In this model:
|
||||
|
||||
- Agent sends body-only framework-compatible markup.
|
||||
- Daybook wraps it in the HTML shell.
|
||||
- Daybook links local framework CSS from `static/vendor/...` or `static/themes/...`.
|
||||
- Daybook remains responsible for stable rendering.
|
||||
|
||||
Pros:
|
||||
|
||||
- Keeps artifacts self-hosted and predictable.
|
||||
- Lets agents use known class vocabularies.
|
||||
- Avoids requiring every agent to write `<head>` boilerplate.
|
||||
- Preserves the current `html_fragment` contract.
|
||||
|
||||
Cons:
|
||||
|
||||
- Daybook must vendor and maintain selected frameworks.
|
||||
- Agents must know which theme/framework is selected.
|
||||
- Some frameworks expect JavaScript or build tooling.
|
||||
|
||||
## Candidate Frameworks
|
||||
|
||||
| Framework | Best for | Fit for Daybook |
|
||||
|---|---|---|
|
||||
| Bootstrap | Reports, cards, grids, alerts, forms | Strong first candidate. Familiar to LLMs and humans. |
|
||||
| Pico CSS | Clean semantic documents | Excellent for low-class, readable reports. |
|
||||
| Bulma | CSS-only layouts/components | Good middle ground; no JS required. |
|
||||
| Tufte CSS | Research notes, essays, analytical reports | Good specialized report style. |
|
||||
| Water.css | Simple semantic HTML styling | Good for zero-effort readable HTML. |
|
||||
| MVP.css | Semantic HTML documents | Good for basic generated reports. |
|
||||
| Sakura.css | Minimal text-heavy documents | Good for simple readable pages. |
|
||||
| Tailwind CSS | Highly custom layouts | Powerful but less ideal without a build step. CDN possible for experiments. |
|
||||
| DaisyUI | Tailwind components | Useful but depends on Tailwind. Better later. |
|
||||
| Flowbite | Tailwind components | Useful but heavier and Tailwind-dependent. |
|
||||
| UIKit | Polished dashboards/docs | Possible but less common. |
|
||||
| Shoelace | Web components | Rich components, but requires JS custom elements. Better later. |
|
||||
| Reveal.js | Real slide decks | Strong future replacement/upgrade for current `deck`. |
|
||||
| Mermaid | Diagrams | Not CSS, but important for diagram artifacts. |
|
||||
| Prism.js / Highlight.js | Code artifacts | Needed for future code renderer. |
|
||||
| Tabulator / DataTables | CSV/table artifacts | Needed for future table renderer. |
|
||||
| JSON viewer libraries | JSON artifacts | Needed for future structured JSON renderer. |
|
||||
|
||||
## Recommended Initial Set
|
||||
|
||||
Start small with CSS-only or mostly CSS-only frameworks:
|
||||
|
||||
1. `bootstrap`
|
||||
2. `pico`
|
||||
3. `bulma`
|
||||
4. `tufte`
|
||||
|
||||
Reasons:
|
||||
|
||||
- No build step required.
|
||||
- Easy for LLMs to emit usable classes/semantic HTML.
|
||||
- Useful for the most common artifact types: reports, cards, summaries, dashboards, and notes.
|
||||
- Can be vendored locally and served through Django static files.
|
||||
|
||||
Defer heavier or JS-dependent frameworks until there is a concrete artifact need.
|
||||
|
||||
## Theme Naming Idea
|
||||
|
||||
Existing themes:
|
||||
|
||||
- `report`
|
||||
- `tasks`
|
||||
- `deck`
|
||||
- `base`
|
||||
|
||||
Potential additions:
|
||||
|
||||
- `bootstrap`
|
||||
- `pico`
|
||||
- `bulma`
|
||||
- `tufte`
|
||||
- `water`
|
||||
|
||||
Agents would specify the theme in the existing `theme` field for `html_fragment` and `markdown` where appropriate.
|
||||
|
||||
## Storage/Vendoring Idea
|
||||
|
||||
Use local static assets rather than CDN links:
|
||||
|
||||
```text
|
||||
static/
|
||||
vendor/
|
||||
bootstrap/
|
||||
bootstrap.min.css
|
||||
bulma/
|
||||
bulma.min.css
|
||||
pico/
|
||||
pico.min.css
|
||||
tufte/
|
||||
tufte.min.css
|
||||
themes/
|
||||
bootstrap.css
|
||||
bulma.css
|
||||
pico.css
|
||||
tufte.css
|
||||
```
|
||||
|
||||
Theme files can either be the vendored framework directly or thin wrappers that import vendor CSS and add Daybook-specific print/preview fixes.
|
||||
|
||||
Example:
|
||||
|
||||
```css
|
||||
@import url("/static/vendor/bootstrap/bootstrap.min.css");
|
||||
|
||||
body.artifact {
|
||||
background: #f8f9fa;
|
||||
}
|
||||
```
|
||||
|
||||
## CDN Policy
|
||||
|
||||
CDN links are acceptable for quick experiments using `html_full`, but should not be the default for reliable self-hosted deployments.
|
||||
|
||||
Recommended policy:
|
||||
|
||||
- MVP experimentation: allow `html_full` with CDN links.
|
||||
- Durable/self-hosted rendering: prefer vendored local CSS themes.
|
||||
- Deployment docs should warn that CDN-dependent artifacts may not render offline.
|
||||
|
||||
## Security Notes
|
||||
|
||||
Framework CSS is relatively safe. Framework JavaScript needs more care.
|
||||
|
||||
Riskier artifact types:
|
||||
|
||||
- `html_full` with arbitrary scripts.
|
||||
- JS component frameworks.
|
||||
- Web components loaded from CDNs.
|
||||
|
||||
Current MVP assumes trusted local/self-hosted use. If Daybook later supports untrusted artifact authors or sharing, it should revisit sandboxing and CSP policies.
|
||||
|
||||
## Relationship To Future Renderers
|
||||
|
||||
Framework themes are separate from future dedicated renderers.
|
||||
|
||||
Future renderers likely need their own artifact kinds:
|
||||
|
||||
- `json`: collapsible JSON viewer, raw source preserved.
|
||||
- `csv`: searchable/sortable table, raw CSV preserved.
|
||||
- `code`: syntax-highlighted code, raw source preserved.
|
||||
- `diagram`: Mermaid/Graphviz/PlantUML source rendered to SVG/HTML, raw source preserved.
|
||||
- `audio`: browser audio player.
|
||||
- `video`: browser video player.
|
||||
|
||||
These should use established libraries rather than custom viewers:
|
||||
|
||||
- JSON viewer library for JSON.
|
||||
- Tabulator or DataTables for CSV/table artifacts.
|
||||
- Prism.js or Highlight.js for code.
|
||||
- Mermaid for Mermaid diagrams.
|
||||
- Native `<audio controls>` and `<video controls>` for media.
|
||||
|
||||
## Recommended Implementation Order
|
||||
|
||||
1. Keep `html_full` as the escape hatch for total agent control.
|
||||
2. Add one vendored CSS framework theme first, probably Bootstrap.
|
||||
3. Document exact usage for `theme=bootstrap` with `html_fragment`.
|
||||
4. Add a sample Bootstrap artifact.
|
||||
5. Add Pico CSS as a low-complexity report/document theme.
|
||||
6. Add Bulma or Tufte only if real artifacts need them.
|
||||
7. Later, add dedicated renderers for JSON, CSV, code, and diagrams.
|
||||
|
||||
## Example Bootstrap Fragment
|
||||
|
||||
```html
|
||||
<main class="container py-4">
|
||||
<div class="row g-3">
|
||||
<section class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h1 class="card-title">Run Summary</h1>
|
||||
<p class="card-text">The agent completed all checks successfully.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<aside class="col-md-4">
|
||||
<div class="alert alert-success">Status: green</div>
|
||||
</aside>
|
||||
</div>
|
||||
</main>
|
||||
```
|
||||
|
||||
Payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"persona": "athena",
|
||||
"kind": "html_fragment",
|
||||
"theme": "bootstrap",
|
||||
"title": "Bootstrap Run Summary",
|
||||
"content": "<main class=\"container py-4\">...</main>"
|
||||
}
|
||||
```
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Should framework themes be available for `markdown`, or only `html_fragment`?
|
||||
- Should Daybook allow framework JavaScript, or CSS only?
|
||||
- Should `html_full` artifacts be sandboxed more strictly in iframes later?
|
||||
- Should agents be able to query `/api/capabilities` for supported themes?
|
||||
- Should themes be exposed as a first-class API field in capabilities?
|
||||
260
planning/next_steps/llm-posting-skill-plan.md
Normal file
260
planning/next_steps/llm-posting-skill-plan.md
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
# Daybook — LLM Posting Skill: Design & Next Steps
|
||||
|
||||
**Status:** planning / pre-implementation
|
||||
**Date:** 2026-06-10
|
||||
**Author:** drafted by Claude (Opus 4.8) after a live smoke test of the deployed instance
|
||||
|
||||
## What This Document Is
|
||||
|
||||
A consolidated design recommendation for making **publishing to Daybook trivially
|
||||
easy for LLM agents**, plus notes on missing functionality surfaced during testing.
|
||||
Goal: an agent should be able to publish a correct artifact out of the box via a
|
||||
single command, without hand-crafting HTTP, JSON, or multipart requests.
|
||||
|
||||
## What Was Validated (Live Smoke Test)
|
||||
|
||||
Tested against the prod instance `http://192.168.1.36:8000` via desktop-commander
|
||||
(the sandbox cannot reach the `192.168.1.x` LAN, so all calls were driven on-host).
|
||||
|
||||
All seven artifact kinds were posted and verified under persona `claude`:
|
||||
|
||||
| Kind | Path | Result |
|
||||
|---|---|---|
|
||||
| markdown | JSON | OK (`2db087a7`) |
|
||||
| html_full | JSON | OK (`8cd79771`) |
|
||||
| deck (markdown — WRONG) | JSON | stored but malformed (`5df27410`) |
|
||||
| image (svg) | multipart | OK (`83ab938c`) |
|
||||
| pdf | multipart | OK (`8c82b15c`) |
|
||||
| binary (csv) | multipart | OK, download-only (`2cceceaf`) |
|
||||
| deck (`<section>` blocks) | JSON | OK (`60d26e5a`) |
|
||||
| html_fragment | JSON | OK (`fd42816f`) |
|
||||
|
||||
Confirmed working: capabilities endpoint, bearer auth, content-type inference
|
||||
(svg→image, pdf→pdf, csv→binary), persona/tag/kind filtering, read-back by id.
|
||||
|
||||
## The Core Problem To Design Around
|
||||
|
||||
Every failure during testing was the same class of problem: **an LLM
|
||||
hand-assembling a request.** Three concrete failure modes, all observed:
|
||||
|
||||
1. **Inline content in shell commands breaks repeatedly.** `powershell -Command`
|
||||
mangled `$`-expansion, nested quotes, and backtick newlines on three separate
|
||||
attempts. This is not incidental — every model re-derives the shell incantation
|
||||
and gets it wrong. It is the single biggest source of friction.
|
||||
2. **Multipart is environment-dependent.** Windows PowerShell 5.1 has no
|
||||
`Invoke-RestMethod -Form`; it needs `curl.exe` or PowerShell 7+. An agent cannot
|
||||
reliably know which host it is running on.
|
||||
3. **Per-kind structure rules are easy to violate.** Markdown was sent to `deck`
|
||||
and rendered malformed — precisely because request-building is where judgment
|
||||
leaks in. The docs' stance is "Daybook does not fix malformed content," so the
|
||||
client must guarantee structure instead.
|
||||
|
||||
**Design conclusion:** the skill must NOT teach the model how to build the request.
|
||||
It must give the model ONE command to run. All fiddliness (auth, JSON-vs-multipart,
|
||||
content-type, escaping, kind validation) belongs inside a helper, not in the prompt.
|
||||
|
||||
## Recommended Approach
|
||||
|
||||
A **bundled CLI helper + a thin SKILL.md**.
|
||||
|
||||
- The skill folder ships a single **zero-dependency Python script**
|
||||
(`scripts/daybook_post.py`, stdlib only). Python runs identically on the NUC
|
||||
(Linux) and on Windows, eliminating the curl / PS5.1 split entirely.
|
||||
- `SKILL.md` tells the agent **when** to publish and **that the command exists** —
|
||||
never how to craft HTTP.
|
||||
- The script is also usable by any non-Claude agent that can run a shell command,
|
||||
so it is not locked to the Anthropic skill format. SKILL.md is just the
|
||||
Claude-flavored discovery wrapper around a universal tool.
|
||||
|
||||
## Why This Is "Easy Out Of The Box"
|
||||
|
||||
1. **Content never touches the command line.** Content comes from a file or stdin,
|
||||
so escaping / newlines / quotes never arise:
|
||||
|
||||
```bash
|
||||
cat report.md | python daybook_post.py --kind markdown --title "Build Report"
|
||||
python daybook_post.py --file diagram.svg --title "Architecture Diagram"
|
||||
```
|
||||
|
||||
2. **One entry point, no branching decisions.** The script decides JSON-vs-multipart
|
||||
and infers content-type from file extension. The model never picks.
|
||||
3. **Validate-before-send with fix hints**, turning the strict server contract into
|
||||
a guardrail the agent cannot trip over.
|
||||
4. **Prints the artifact URL as the last stdout line**, so the agent reliably
|
||||
captures the result regardless of verbosity.
|
||||
|
||||
### Pre-flight validation table
|
||||
|
||||
| Kind / input | Check | Behavior on mismatch |
|
||||
|---|---|---|
|
||||
| `deck` | content contains `<section` | error: "deck needs top-level `<section>...</section>` blocks, not Markdown" |
|
||||
| `html_fragment` | no `<html>` / `<!doctype` | error: "fragment must be body-only HTML" |
|
||||
| `html_full` | has `<!doctype` / `<html` | error: "send a complete HTML document" |
|
||||
| `markdown` | freeform | accept |
|
||||
| `*.svg` upload | force `image/svg+xml` | auto-fix (not an error) |
|
||||
| `*.pdf` upload | force `application/pdf` | auto-fix |
|
||||
| other upload | extension→mime, else `octet-stream` | store as binary |
|
||||
|
||||
## Proposed CLI Surface (Deliberately Small)
|
||||
|
||||
```
|
||||
daybook_post.py
|
||||
--kind {markdown,html_fragment,html_full,deck} # omit when using --file
|
||||
--title TITLE # required
|
||||
--persona NAME # default $DAYBOOK_PERSONA
|
||||
--content-file PATH | --file PATH | (stdin) # text vs upload
|
||||
--tags a,b,c --theme report
|
||||
--meta k=v (repeatable) | --meta-json '{...}'
|
||||
--source-name ... --source-id ... --source-prompt ...
|
||||
--check # GET /api/capabilities and exit
|
||||
--dry-run # print the request it would send, do not post
|
||||
```
|
||||
|
||||
Config via env with prod fallbacks: `DAYBOOK_URL`, `DAYBOOK_TOKEN`,
|
||||
`DAYBOOK_PERSONA`. Zero-config by default, fully overridable.
|
||||
|
||||
## SKILL.md Design
|
||||
|
||||
The single most important field for out-of-the-box use is the **description**,
|
||||
because that is what makes an agent reach for the skill unprompted. Key on *intent*,
|
||||
not mechanism:
|
||||
|
||||
> Use when you have produced a finished deliverable — a report, summary, brief,
|
||||
> diagram, generated HTML, PDF, or status update — that a human should be able to
|
||||
> review later outside this chat. Publishes it to Daybook and returns a URL.
|
||||
|
||||
The body of SKILL.md should be short:
|
||||
- One line on what Daybook is (publish-only artifact journal).
|
||||
- The single command pattern (file/stdin in, URL out).
|
||||
- A 4-row kind cheat-sheet (markdown / fragment / full / deck → what content shape).
|
||||
- "Run `--check` first if unsure the instance is up."
|
||||
- Explicitly: do NOT hand-build curl/JSON; always use the script.
|
||||
|
||||
Proposed skill folder layout:
|
||||
|
||||
```
|
||||
agent-daybook/ (skill root)
|
||||
SKILL.md
|
||||
scripts/
|
||||
daybook_post.py # the one helper, stdlib only
|
||||
.env.example # DAYBOOK_URL / DAYBOOK_TOKEN / DAYBOOK_PERSONA
|
||||
```
|
||||
|
||||
## Open Decisions (Need Your Call)
|
||||
|
||||
1. **Token handling.** Baking the prod token as a fallback default = truly
|
||||
zero-config, but it lands in the skill folder / repo. Cleaner: require
|
||||
`DAYBOOK_TOKEN` and ship `.env.example`. Recommendation: zero-config now while
|
||||
it is a local MVP, tighten to env-only before this leaves the LAN.
|
||||
2. **Helper location.** Bundle inside the skill (`scripts/`) for a self-contained,
|
||||
no-install drop-in — recommended — vs a system-wide install that reintroduces
|
||||
PATH friction.
|
||||
3. **Auto-wrap convenience kinds.** Should the script auto-wrap a `.csv`/`.json`
|
||||
into a Markdown fenced block so it renders today (server has no CSV/JSON
|
||||
renderer yet)? Convenient, but slightly magic. Suggest: opt-in flag
|
||||
`--as-markdown`, not default.
|
||||
|
||||
## Server-Side / Missing Functionality Notes
|
||||
|
||||
Observed during testing. The thin client absorbs MVP gaps so the server can stay
|
||||
strict; these are candidates for later server work, not blockers.
|
||||
|
||||
- **No DELETE / no content revision.** Once posted, an artifact is permanent;
|
||||
`content`/`kind`/`persona`/`day` are not PATCH-editable. The malformed test deck
|
||||
`5df27410` can only be superseded, not removed. Consider a soft-delete or
|
||||
`archived` flag for cleanup of test/mistake artifacts.
|
||||
- **No CSV/JSON/code renderer.** These store as download-only `binary`. Fine for
|
||||
now; the client can wrap them as Markdown on request. A dedicated renderer is
|
||||
the eventual fix.
|
||||
- **Single shared token, no reader auth.** Acceptable on a trusted LAN; revisit
|
||||
before any wider exposure.
|
||||
- **No pagination/cursors on list.** Fine at current volume; will matter once
|
||||
feeds grow.
|
||||
- **Strict-by-design rendering.** "Daybook does not fix malformed content" is a
|
||||
reasonable stance IF the standard publish path is a validating client. The skill
|
||||
is what makes that stance safe — keep them in sync (if the server adds a kind,
|
||||
the script's validation table must follow).
|
||||
|
||||
## Suggested Build Order
|
||||
|
||||
1. Write `scripts/daybook_post.py` (stdlib: `urllib`, hand-rolled multipart,
|
||||
extension→mime map, kind validation, stdin/file content, URL on last line).
|
||||
2. Smoke-test it against the live instance for all four text kinds + the three
|
||||
file kinds — same coverage as the manual test, but each via one command.
|
||||
3. Write `SKILL.md` (intent-keyed description + the cheat-sheet) and `.env.example`.
|
||||
4. Verify discovery: confirm an agent picks the skill from the description alone.
|
||||
5. Later/server: soft-delete or archive flag; CSV/JSON renderer; token hardening
|
||||
before the instance leaves the LAN.
|
||||
|
||||
## Appendix: Environment Facts (from test host)
|
||||
|
||||
- Prod instance reachable only on LAN `192.168.1.36:8000` — agents must be on-network.
|
||||
- Host is Windows PowerShell **5.1** (no `-Form`); `curl.exe` present via Git;
|
||||
Python **3.12** present. Python helper avoids all shell-specific pitfalls.
|
||||
- Inlining content into `powershell -Command` is the confirmed failure mode;
|
||||
file/stdin input is the fix.
|
||||
|
||||
---
|
||||
|
||||
## Architecture Decision: Public REST API as the Universal Substrate
|
||||
|
||||
**Decided:** 2026-06-10 · **Status:** accepted direction; hardening deferred (see below)
|
||||
|
||||
### Core conclusion
|
||||
|
||||
The private LAN address (`192.168.1.36`) was the *only* thing forcing MCP and
|
||||
desktop-commander workarounds. Nothing about Daybook intrinsically requires them.
|
||||
Host Daybook on a publicly routable VM and the reachability wall disappears for
|
||||
every agent at once. The generic, universal interface is simply the **public
|
||||
HTTPS REST API** — any LLM or agent with an HTTP client can `POST /api/artifacts`
|
||||
in any language. A client script is optional sugar; MCP drops from "required" to
|
||||
"nice-to-have."
|
||||
|
||||
### The layering (everything hangs off the REST API)
|
||||
|
||||
| Layer | Role | Required? |
|
||||
|---|---|---|
|
||||
| Public HTTPS REST API | The universal substrate. This is the product. | Yes — core |
|
||||
| Thin client (`daybook_post.py`, path-based) | One-liner ergonomics over REST | Optional |
|
||||
| MCP server (local stdio) | Typed calls + auto-discovery for MCP-native agents | Optional polish |
|
||||
| Skill (`SKILL.md`) | Claude-specific pointer to the script/REST | Optional |
|
||||
|
||||
Build bottom-up: REST alone is enough to be generic. Add the others only where a
|
||||
specific client benefits.
|
||||
|
||||
### Reachability by environment (once Daybook is public)
|
||||
|
||||
| Environment | Can it POST directly? | Notes |
|
||||
|---|---|---|
|
||||
| Claude Code / laptop / CI / arbitrary agent | Yes | Open internet + HTTP client. The 95% case. |
|
||||
| claude.ai / Desktop chat sandbox (`bash_tool`) | Yes, after one toggle | Add the Daybook domain to the bash **egress allowlist** in network settings; then a sandbox python script reads a sandbox-generated file and POSTs. No desktop-commander, no MCP. |
|
||||
| claude.ai `web_fetch` | No | GET-oriented public fetcher; cannot do an authenticated POST with a body. Use `bash_tool` instead. |
|
||||
|
||||
Key point: in the all-public case the file-location problem also dissolves — the
|
||||
generated file and the posting script are co-located in the same sandbox, and the
|
||||
target is publicly routable.
|
||||
|
||||
### Deferred: auth hardening for the LAN -> public transition
|
||||
|
||||
The reachability story gets *simpler* when public; the auth story gets *stricter*.
|
||||
The single shared dev token is fine on a trusted LAN and unacceptable on the open
|
||||
internet. Before any real public exposure:
|
||||
|
||||
- [ ] Per-agent API keys (revocable, attributable), not one shared token
|
||||
- [ ] TLS / HTTPS only
|
||||
- [ ] Rate limiting + upload size/abuse guards
|
||||
- [ ] Write-scoping per persona (an agent can only post as its own persona)
|
||||
- [ ] Basic audit log of who posted what
|
||||
|
||||
### NOT needed for current testing (explicit)
|
||||
|
||||
For testing the basic idea and playing with dummy documents, **none of the above
|
||||
is required**. The current setup is sufficient:
|
||||
|
||||
- Keep running on the LAN (`192.168.1.36:8000`) with the single dev token.
|
||||
- Post dummy artifacts via desktop-commander (this chat) or the CLI (Claude Code).
|
||||
- Treat the auth-hardening checklist as a gate that applies *only* when Daybook
|
||||
moves to a public host for real use — not before.
|
||||
|
||||
Sequencing: prove the posting ergonomics and rendering with dummy docs first;
|
||||
take on public deployment + auth hardening only once the basic idea is validated.
|
||||
Loading…
Add table
Add a link
Reference in a new issue