{"id":51511763,"url":"https://github.com/kaiser-data/article-studio","last_synced_at":"2026-07-08T07:02:17.155Z","repository":{"id":370064440,"uuid":"1282461913","full_name":"kaiser-data/article-studio","owner":"kaiser-data","description":"A single-file writing desk for planning, drafting and publishing articles (LinkedIn, Medium, Toastmasters, Luma) — wired to Claude Code via Markdown files.","archived":false,"fork":false,"pushed_at":"2026-07-08T05:13:23.000Z","size":51,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-08T06:13:21.069Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kaiser-data.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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-06-27T19:59:09.000Z","updated_at":"2026-07-08T05:13:26.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kaiser-data/article-studio","commit_stats":null,"previous_names":["kaiser-data/article-studio"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/kaiser-data/article-studio","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaiser-data%2Farticle-studio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaiser-data%2Farticle-studio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaiser-data%2Farticle-studio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaiser-data%2Farticle-studio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kaiser-data","download_url":"https://codeload.github.com/kaiser-data/article-studio/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaiser-data%2Farticle-studio/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35255367,"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-07-08T02:00:06.796Z","response_time":61,"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-07-08T07:02:16.257Z","updated_at":"2026-07-08T07:02:17.145Z","avatar_url":"https://github.com/kaiser-data.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Article Studio\n\nA single-file writing desk for planning, drafting, and shipping articles across\n**LinkedIn, Medium, Toastmasters newsletters, Luma events, and blogs** — wired\ndirectly to Codex or Claude Code through plain Markdown files.\n\n## Run it\n\n**Double-click `serve.command`** (macOS). It starts the local backend server and opens\nthe app in Chrome, usually at `http://127.0.0.1:8765`. If that port is already\noccupied, the launcher falls back to `8766`, `8767`, or `8768`.\n\nWhy a server? Chrome only allows the folder bridge in a *secure context*. Opening\n`index.html` directly as a `file://` page disables it — so serve over localhost:\n\n```\ncd article_publisher\nnode server.js\n# then open http://127.0.0.1:8765/index.html in Chrome / Edge / Brave\n```\n\nThe app still runs as a plain `file://` page, but **Connect folder** only works over\n`http://localhost`. Direct Codex runs also require the local backend.\n\nThe browser cannot start a backend process by itself, so use `serve.command` to\nstart the backend. The app checks `/api/health` and enables **Run Codex** when the\nbackend is running and the `codex` CLI is available on `PATH`.\n\n## The agent bridge\n\nThe app and your coding agent edit the **same files**:\n\n1. Click **🔗 Connect folder** in the app and pick the `articles/` folder.\n2. Each article is stored as a `.md` file with YAML front-matter:\n\n   ```yaml\n   ---\n   title: ...\n   platform: linkedin   # linkedin | medium | toastmasters | luma | blog\n   status: idea         # idea | drafting | ready | posted\n   tags: [toastmasters, it]\n   summary: ...\n   images: [images/foo.png]\n   created: ...\n   updated: ...\n   id: ...\n   ---\n   body in markdown\n   ```\n\n3. Open the **Agents** tab in the inspector and choose **Codex** or\n   **Claude Code** as the handoff target.\n4. Copy a task prompt or save a task note:\n   - Codex notes go into `articles/.codex-tasks/`.\n   - Claude Code notes go into `articles/.claude-tasks/`.\n5. Ask the selected agent to work on them, e.g.:\n   - *\"Tighten the hook on `articles/welcome-linkedin-post.md` and keep it under 1300 chars.\"*\n   - *\"Turn the Medium draft into a Toastmasters newsletter version.\"*\n   - *\"Draft 3 LinkedIn post ideas about Kubernetes and drop them in `articles/` as new files.\"*\n6. Back in the app, hit **↻ Reload** to pull edits in.\n\n\u003e Tip: After agent edits files here, this project's convention is to run\n\u003e `graphify update .` if you keep a knowledge graph — not required for the app.\n\n## Features\n\n- **Pipeline board** — Idea → Drafting → Ready → Posted, filtered by platform.\n- **Content calendar \u0026 scheduling** — give each article a `publishDate` (Meta tab),\n  see a full month calendar (📅 button) with posts colored by platform, plus\n  overdue/today/upcoming chips on cards and an upcoming list. Dates round-trip in\n  front-matter so the agents see your schedule too.\n- **Markdown editor** with Write / Split / Preview and live word + character counts.\n- **Per-platform playbooks** — length targets, hook rules, hashtag and formatting\n  tips for LinkedIn, Medium, Toastmasters, Luma, and generic blogs.\n- **Image upload** (drag \u0026 drop) — auto-compressed/resized on upload (≤1920px),\n  saved into `articles/images/` and referenced by relative path, so Medium/Luma\n  uploads and agents both see the same files. In browser-only mode, image blobs go\n  to **IndexedDB** (not base64 in localStorage) to avoid the ~5MB quota wall.\n- **People directory** — save people you want to @mention (name, platform, handle/URL,\n  note). Insert mentions into a draft with one click, and **tag people on individual\n  photos**. Stored in `articles/people.json` (shared with the agents); photo tags live\n  in each article's `imageTags:` front-matter so they survive reloads.\n- **Agent handoff** — choose Codex or Claude Code, generate task prompts for\n  polishing, hook rewrites, repurposing, or risk review; copy them or save task\n  notes under `articles/.codex-tasks/` or `articles/.claude-tasks/`.\n- **Switchable agent backend** — when started through `serve.command`, the\n  Codex / Claude Code selector runs the edit through the chosen local CLI\n  (`codex exec` or `claude -p`) and applies the returned draft in the editor.\n- **Conflict-safe sync** — if an agent edits a file you have open, the app\n  detects it and shows a banner (*Save my version* / *Load file*) instead of\n  silently overwriting. **↻ Reload** warns before discarding unsaved in-app edits.\n- **Publish-ready export** (⤴ button) — converts a draft to what each platform\n  actually accepts: **LinkedIn** (Markdown bold → Unicode bold that survives, links\n  pulled into a ready-to-paste *first comment*), **Medium** (clean Markdown), **Plain\n  text**, and **Luma** (event description + a downloadable `.ics` from the publish date).\n- **Backup / restore** via JSON, plus \"Save all to folder\".\n\n## Folders\n\n```\narticle_publisher/\n├── index.html              # the app (UI)\n├── server.js               # local backend: static files + /api/run (codex / claude)\n├── shared/frontmatter.js   # article \u003c-\u003e Markdown schema, shared by app + backend\n├── serve.command           # macOS launcher (starts backend, opens Chrome)\n├── package.json            # npm start / npm test\n├── test/frontmatter.test.js\n├── articles/               # ← connect this folder (drafts stay local, git-ignored)\n│   ├── welcome-linkedin-post.md\n│   └── images/\n└── README.md\n```\n\n## Development\n\n`shared/frontmatter.js` is the single source of truth for how an article maps to\nits Markdown file — imported by both `index.html` (in the browser) and `server.js`\n(in Node), so the two can't drift and drop fields.\n\n```\nnpm start     # run the backend at http://localhost:8765\nnpm test      # front-matter round-trip test\n```\n\n## Browser note\n\nThe live folder sync uses the File System Access API (Chromium browsers). On\nSafari/Firefox the app still works fully via `localStorage` — use **Export** /\n**Import** from the `⋯` menu to move files to/from your agent instead.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaiser-data%2Farticle-studio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkaiser-data%2Farticle-studio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaiser-data%2Farticle-studio/lists"}