{"id":50999905,"url":"https://github.com/cablehead/stacks.nu","last_synced_at":"2026-06-20T13:30:54.222Z","repository":{"id":354210043,"uuid":"1222652355","full_name":"cablehead/stacks.nu","owner":"cablehead","description":"Event-sourced \"clip\" manager: xs + http-nu + datastar.","archived":false,"fork":false,"pushed_at":"2026-05-11T15:52:14.000Z","size":489,"stargazers_count":4,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-06-18T21:31:43.964Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Nushell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cablehead.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-27T15:16:41.000Z","updated_at":"2026-05-11T17:41:32.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cablehead/stacks.nu","commit_stats":null,"previous_names":["cablehead/stacks.nu"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cablehead/stacks.nu","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cablehead%2Fstacks.nu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cablehead%2Fstacks.nu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cablehead%2Fstacks.nu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cablehead%2Fstacks.nu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cablehead","download_url":"https://codeload.github.com/cablehead/stacks.nu/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cablehead%2Fstacks.nu/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34572423,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-20T02:00:06.407Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-20T13:30:51.787Z","updated_at":"2026-06-20T13:30:54.212Z","avatar_url":"https://github.com/cablehead.png","language":"Nushell","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1\u003estacks.nu\u003c/h1\u003e\n\nA \"clip\" manager where a clip can be a README, an image, a random thought,\na JSON dataset. Pipe clips through Nushell pipelines. Built on\n[xs](https://github.com/cablehead/xs) for the log,\n[http-nu](https://github.com/cablehead/http-nu) for the routes,\n[Datastar](https://data-star.dev) for the UI.\n\nThe page holds no state. Selection, mode, the visible HTML -- all projected\non the server from frames in the event store and patched into `\u003cmain\u003e` over\nSSE.\n\nhttps://github.com/user-attachments/assets/10d6b5e8-d6a3-4e4d-ba85-79c7a803b94b\n\n## Run\n\n```sh\nhttp-nu --datastar --store ./store :4777 -w ./www/serve.nu\n```\n\nOpen \u003chttp://localhost:4777\u003e.\n\nFirst boot drops in a `Tutorial` stack whose clips walk you through the\nkeymap; delete it when you're done.\n\n## What's a clip\n\nAny byte sequence with a mime type. Text clips render inline; images render\nvia `/cas/\u003chash\u003e` with `Cache-Control: immutable` (identical content across\nstacks shares a URL and a cache entry). New mime types fall through to a\ngeneric preview without code changes.\n\nStacks group clips. Sort modes:\n\n- `auto` -- ordered by activity, newest first. Edits float a clip to the top.\n- `manual` -- fractional `position` strings; user-curated order.\n\n## Piping\n\nPress `P` on a clip to open the pipe panel. Type any Nushell pipeline; `$in`\nis the clip's body. `Mod+Enter` runs. Result renders below; errors surface\nwith source excerpts pointing at the offending span.\n\n```nushell\n$in | from json | get users | length\nstr upcase\nlines | where {|l| $l =~ \"TODO\"}\n```\n\nHistory is persisted to the log -- arrow up or start typing to recall.\nImplemented via http-nu's `.run` so any change to the Nushell language or\nlibrary is immediately available.\n\n## Trash\n\n`clip.delete` and `stack.delete` snapshot what was removed into projection\nstate. `Shift+T` (or the actions panel) opens the trash; Enter restores.\nDeleting a stack with previously-deleted clips inside is handled -- restore\nthe stack first, then the orphaned clips become restorable.\n\n## Event protocol\n\nPersistent topics (the durable log):\n\n| Topic           | Meta                                                  |\n| --------------- | ----------------------------------------------------- |\n| `stack.add`     | `{name, sort}`                                        |\n| `stack.update`  | `{id, name?, sort?}`                                  |\n| `stack.delete`  | `{id}`                                                |\n| `stack.restore` | `{target}` (id of the original `stack.delete` frame)  |\n| `clip.add`      | `{stack_id, mime_type, position?}` + body -\u003e CAS      |\n| `clip.update`  | `{id}` + body -\u003e CAS  (clip identity stays stable)     |\n| `clip.patch`    | `{id, stack_id?, position?, mime_type?, ...}`         |\n| `clip.delete`   | `{id}`                                                |\n| `clip.restore`  | `{target}` (id of the original `clip.delete` frame)   |\n| `pipe.command`  | `{source, clip_id}` (pipe history)                    |\n\nA `stack.add` frame's id _is_ the stack id; same for `clip.add`. Stacks are\nordered by recent activity. Prior versions of a clip are reachable by\nwalking earlier `clip.add`/`clip.update` frames with the same id.\n\nEphemeral UI signals (selection, mode toggles, transient input, pipe\nresults) go through http-nu's [Local Bus](https://github.com/cablehead/http-nu#local-bus) --\nin-process pub/sub, no persistence, no cross-host wire traffic. The\n`/updates` SSE handler interleaves `.cat -f` with `.bus sub` and folds both\nthrough the same projection.\n\n## Keys\n\nMode-aware. The status bar at the bottom always lists the active mode's\nkeys; clicking a binding fires the same action a keypress would. `Mod` is\n`Cmd` on macOS, `Ctrl` elsewhere (resolved per-request via\n`sec-ch-ua-platform` / User-Agent).\n\nMain:\n\n| Key                   | Action                       |\n| --------------------- | ---------------------------- |\n| `J` / `K`             | Next / prev clip             |\n| `Shift+J` / `Shift+K` | Next / prev stack            |\n| `N`                   | New clip                     |\n| `Shift+N`             | New stack (timestamp name)   |\n| `E`                   | Edit selected clip           |\n| `P`                   | Pipe selected clip           |\n| `R`                   | Rename selected stack        |\n| `DEL`                 | Delete selected clip         |\n| `Shift+DEL`           | Delete selected stack        |\n| `Shift+T`             | Open trash                   |\n| `Mod+K`               | Open actions panel           |\n\nCompose / edit / rename / pipe modals: `Mod+Enter` commits, `Esc` cancels.\n\n## Layout\n\n```\nwww/\n  serve.nu             route table + view-model\n  projection.nu        pure fold over the event stream\n  test.nu              projection + route round-trip tests\n  templates/           minijinja templates rendered server-side\n  static/              keys.js, action-panel.js, base.css\n  stacks/mod.nu        protocol builders (`stack add`, `clip move`, ...)\nscripts/\n  lint.nu              topiary fmt on every .nu\n  check.sh             verify formatted\n  shoot-design.sh      screenshot /design and post as a clip\ntests-browser/         playwright + system chromium e2e\n```\n\n## Tests\n\n```sh\nhttp-nu eval --store /tmp/test ./www/test.nu     # projection + routes\nnode tests-browser/pipe-history.test.mjs         # browser e2e\n```\n\n## Formatting\n\n```sh\nnu scripts/lint.nu     # format every .nu via topiary\nscripts/check.sh       # verify (exit non-zero if drift)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcablehead%2Fstacks.nu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcablehead%2Fstacks.nu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcablehead%2Fstacks.nu/lists"}