{"id":49495085,"url":"https://github.com/unbug/tday","last_synced_at":"2026-05-01T09:02:50.001Z","repository":{"id":354898138,"uuid":"1225599451","full_name":"unbug/tday","owner":"unbug","description":"The Ultimate Harness Agent Terminal Launcher","archived":false,"fork":false,"pushed_at":"2026-04-30T20:16:16.000Z","size":404,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-30T20:20:34.648Z","etag":null,"topics":["codeagents","harness","harness-ci"],"latest_commit_sha":null,"homepage":"https://github.com/unbug/tday","language":"TypeScript","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/unbug.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-04-30T12:52:44.000Z","updated_at":"2026-04-30T20:16:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/unbug/tday","commit_stats":null,"previous_names":["unbug/tday"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/unbug/tday","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unbug%2Ftday","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unbug%2Ftday/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unbug%2Ftday/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unbug%2Ftday/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/unbug","download_url":"https://codeload.github.com/unbug/tday/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unbug%2Ftday/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32490815,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"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":["codeagents","harness","harness-ci"],"created_at":"2026-05-01T09:02:49.132Z","updated_at":"2026-05-01T09:02:49.984Z","avatar_url":"https://github.com/unbug.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tday — The Ultimate Harness Agent Terminal Launcher\n\n\u003e One terminal launcher for every coding-agent harness — Claude Code, Codex, Copilot CLI, OpenCode, Pi, and more. Browser-style tabs, unified provider config, auto-detected local inference, long-term memory, and cross-agent token analytics.\n\n[![latest](https://img.shields.io/badge/release-latest-blue)](https://github.com/unbug/tday/releases)\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://x.com/i/status/2049935301808935356\"\u003e\n    \u003cimg\n      width=\"1200\"\n      height=\"800\"\n      alt=\"Tday Demo Video on X\"\n      src=\"https://github.com/user-attachments/assets/5d7ac6d9-cf0a-4eb3-b865-71ffbd11806b\"\n    /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg\n    width=\"49%\"\n    alt=\"Tday Screenshot 1\"\n    src=\"https://github.com/user-attachments/assets/77499913-ef2b-40a0-a0d3-88b779e337a0\"\n  /\u003e\n  \u003cimg\n    width=\"49%\"\n    alt=\"Tday Screenshot 2\"\n    src=\"https://github.com/user-attachments/assets/1964db7f-2db3-4eed-92a7-65eb172d33ed\"\n  /\u003e\n\u003c/p\u003e\n\n\n---\n\n## 1. Vision\n\nToday, every coding-agent harness ships with its own CLI, its own provider config, its own memory format, and its own token accounting. Power users juggle Claude Code in one tab, Codex in another, Copilot CLI in a third, OpenCode in a fourth — each a separate terminal, each re-keyed, each forgetful.\n\n**Tday** is the missing meta-layer:\n\n- **Open agents in tabs** the way you open URLs in a browser. `Cmd+T` for a new agent, drag-to-reorder, persistent sessions.\n- **One provider config** (DeepSeek, OpenRouter, Anthropic, OpenAI, …) injected into whichever agent you launch.\n- **Auto-discover local inference** servers (Ollama, LM Studio, llama.cpp, vLLM) on your LAN/loopback and surface them as first-class providers.\n- **Unified long-term memory** shared across agents (with per-agent scoping when you want it).\n- **Cross-agent token analytics** — finally know what each harness actually costs.\n- **Buttery UX** with `border-beam` accents, native PTY performance, and a Rust core for the hot paths.\n\n---\n\n## 2. Architecture\n\n```\n┌──────────────────────── Tday Desktop App ────────────────────────┐\n│                                                                     │\n│  Renderer (React + Vite + TS)                                       │\n│  ├─ Tab Manager (browser-style)                                     │\n│  ├─ Terminal View (xterm.js + WebGL renderer)                       │\n│  ├─ Agent Picker, Settings, Memory Browser, Usage Dashboard         │\n│  └─ UI kit: Tailwind + shadcn/ui + border-beam (magicui)            │\n│                          ▲                                          │\n│                          │ IPC (typed, contextBridge)               │\n│                          ▼                                          │\n│  Main Process (Electron + Node)                                     │\n│  ├─ Session Service       (one PTY per tab via node-pty)            │\n│  ├─ Agent Adapter Registry (pi, claude-code, codex, copilot, opencode, …)    │\n│  ├─ Provider Service       (env-var injection + secret store)       │\n│  ├─ IPC Bridge             (typed channels)                         │\n│  ├─ Gateway (local HTTP proxy: OpenAI Responses API → Anthropic)    │\n│  │    ├─ bridge/  (input · tools · response · stream conversion)    │\n│  │    ├─ anthropic/  (HTTP client + SSE parser)                     │\n│  │    └─ deepseek/   (thinking encoder · per-session state cache)   │\n│  └─ Spawns: tday-core (Rust)                                        │\n│                          ▲                                          │\n│                          │ JSON-RPC over stdio / Unix socket        │\n│                          ▼                                          │\n│  tday-core (Rust binary, single static executable)               │\n│  ├─ Local-inference scanner (ollama/lmstudio/llama.cpp/vllm)        │\n│  ├─ Token counter (tiktoken-rs / tokenizers)                        │\n│  ├─ Memory store (SQLite + sqlite-vec for embeddings)               │\n│  ├─ Usage logger (per-agent, per-provider, per-tab)                 │\n│  └─ Config \u0026 secrets (keyring crate, OS keychain)                   │\n│                                                                     │\n└─────────────────────────────────────────────────────────────────────┘\n```\n\n### Why this split\n\n| Concern | Where | Why |\n|---|---|---|\n| Window, tabs, UI | Electron + React | Mature, fast iteration, rich ecosystem. |\n| PTY spawning | Electron main (node-pty) | Battle-tested, full TTY semantics, integrates cleanly with xterm.js. |\n| Detection / tokenization / memory | Rust (`tday-core`) | CPU-bound, must not block UI. Static binary, easy to ship \u0026 cross-compile. |\n| Provider secrets | OS keychain via Rust | Avoid plaintext in app data; cross-platform. |\n\n### Gateway — OpenAI Responses API → Anthropic proxy\n\nSome harnesses (e.g. Codex) only speak the **OpenAI Responses API**. Tday ships a lightweight in-process HTTP gateway that transparently translates those calls to the **Anthropic Messages API**, enabling DeepSeek and any other Anthropic-compatible provider to be used with every harness without patching the harness.\n\n```\nHarness (Codex)              Main Process\n       │  POST /v1/responses      │\n       │ ─────────────────────▶  │\n       │                   bridge/input   (OpenAI Responses → Anthropic Messages)\n       │                   bridge/tools   (tool / tool-choice conversion)\n       │                   deepseek/      (thinking-block encode/decode, V4 mutations)\n       │                   anthropic/     (HTTP POST + SSE stream from provider)\n       │                   bridge/stream  (Anthropic SSE → OpenAI SSE events)\n       │  SSE stream              │\n       │ ◀─────────────────────  │\n```\n\n**Module map** (`apps/desktop/src/main/gateway/`):\n\n| Module | Responsibility |\n|---|---|\n| `adapter.ts` | Express server, request dispatch, error handling |\n| `types.ts` | Shared gateway interfaces (Request, Response, …) |\n| `anthropic/types.ts` | Anthropic Messages API type definitions |\n| `anthropic/client.ts` | HTTP client, SSE tokeniser |\n| `openai/types.ts` | OpenAI Responses API type definitions |\n| `bridge/input.ts` | Convert OpenAI input items → Anthropic messages array |\n| `bridge/tools.ts` | Convert OpenAI tools → Anthropic ATool[], apply DeepSeek mutations |\n| `bridge/response.ts` | Convert Anthropic non-streaming response → OpenAI output |\n| `bridge/stream.ts` | Convert Anthropic SSE events → OpenAI Responses API SSE |\n| `deepseek/thinking.ts` | Encode / decode extended thinking blocks (prefix-based) |\n| `deepseek/state.ts` | Per-session LRU cache for (thinking, signature) pairs |\n\n\n\nEvery harness is a thin adapter:\n\n```ts\ninterface AgentAdapter {\n  id: string;                          // \"pi\" | \"claude-code\" | \"codex\" | \"opencode\"\n  displayName: string;\n  detect(): Promise\u003cDetectResult\u003e;     // is the binary on PATH? version?\n  buildLaunch(ctx: LaunchContext): {   // how to start it in a PTY\n    cmd: string;\n    args: string[];\n    env: Record\u003cstring, string\u003e;       // provider keys, base URLs, etc.\n    cwd: string;\n  };\n  parseUsage?(stream: string): UsageDelta | null; // optional: scrape token usage\n}\n```\n\n### Tab = Session\n\nA **Tab** owns one **Session** = one PTY process bound to one agent adapter, one provider profile, and one working directory. Tabs persist across app restarts (process state does not; transcript does).\n\n---\n\n## 3. Long-term Roadmap\n\n| Version | Theme | Highlights |\n|---|---|---|\n| ~~**v0.1.0**~~ ✅ | _Walk_ — Pi end-to-end | Single-tab MVP. Spawn the `pi` agent in a PTY tab. Static provider config from a JSON file. Border-beam shell. |\n| ~~**v0.2.0**~~ ✅ | Multi-agent, multi-tab | Adapters for Claude Code, Codex, Copilot CLI, OpenCode. Tab manager (open/close/reorder/duplicate). Per-tab cwd picker. |\n| ~~**v0.3.0**~~ ✅ | Providers UI + Gateway | Settings panel for 28 cloud/local providers. DeepSeek Anthropic gateway proxy (OpenAI Responses API → Anthropic). Per-agent model override. |\n| **v0.4.0** | Local-inference autodetect | Rust scanner polls `localhost:11434` (Ollama), `:1234` (LM Studio), `:8080` (llama.cpp), `:8000` (vLLM). Auto-add discovered endpoints with their model lists. mDNS for LAN. |\n| **v0.5.0** | Token usage analytics | Per-tab, per-agent, per-provider, per-model accounting. Cost estimation. Charts. Export CSV/JSON. |\n| **v0.6.0** | Unified long-term memory | SQLite + `sqlite-vec`. Cross-agent recall via MCP-server bridge that every adapter can mount. Per-project scoping. |\n| **v0.7.0** | Performance \u0026 polish | WebGL terminal renderer, lazy tab hydration, snapshot-based session restore, profiler, memory budgets. |\n| **v0.8.0** | Plugins \u0026 extensibility | Adapter SDK, third-party adapters loadable from a manifest, custom themes. |\n| **v0.9.0** | Sync \u0026 teams | Optional E2EE sync of memory + usage across devices. Team dashboards. |\n| **v1.0.0** | GA | Auto-update, signed builds for macOS/Windows/Linux, full docs, telemetry opt-in. |\n\n---\n\n## 4. Detailed Task Breakdown\n\n### v0.1.0 — Pi end-to-end ✅\n\nThe acceptance criterion: **`npm run dev` opens a window with one tab running the `pi` agent in a real PTY; typing works, output streams, resizing works, closing the tab kills the process cleanly.**\n\n- [x] Repo scaffold\n  - [x] Decide stack \u0026 layout\n  - [x] Write this README\n- [x] **App skeleton** (`apps/desktop`)\n  - [x] Electron main + preload + renderer in TypeScript\n  - [x] Vite for renderer dev/build\n  - [x] Tailwind + shadcn/ui base\n  - [x] `border-beam` component (magicui-port) on app frame\n- [x] **PTY + terminal**\n  - [x] `node-pty` integration in main\n  - [x] `xterm.js` in renderer with fit + web-links addons\n  - [x] Bidirectional IPC: `pty:spawn`, `pty:write`, `pty:resize`, `pty:data`, `pty:exit`\n- [x] **Tab shell** (multi-tab from the start)\n  - [x] `Tab` and `Session` data model\n  - [x] `Cmd+W` / close button kills the PTY\n- [x] **Pi adapter** (`packages/adapters/pi`)\n  - [x] `detect()` — `which pi` + `pi --version`\n  - [x] `buildLaunch()` — reads provider profile, sets env, args\n  - [x] Configurable binary path\n- [x] **Provider profile (static JSON)**\n  - [x] `~/.tday/providers.json` seeded on first launch\n  - [x] Loaded at launch, injected via env\n- [ ] **Rust core stub** (`crates/tday-core`)\n  - [ ] `cargo new --bin`, prints version on `--version`\n  - [ ] `tday-core detect` — JSON-RPC stub for v0.4.0\n  - [ ] Wired into the Electron build so the binary ships next to the app\n- [x] **DX**\n  - [x] `pnpm dev` launches everything\n  - [x] `pnpm build` produces signed-null `.dmg` + `.zip` for arm64 and x64\n  - [ ] CI: lint + typecheck + `cargo check`\n\n### v0.2.0 — Multi-agent, multi-tab ✅\n- [x] Adapters: `pi`, `claude-code`, `codex`, `copilot`, `opencode` (install / update / uninstall via `npm i -g`)\n- [x] Tab bar with drag-reorder + multi-row wrap\n- [x] Split new-tab button: default agent on click, dropdown chevron picker for any installed harness\n- [x] Configurable default agent in Settings → Agents\n- [x] Per-tab cwd staging + commit (Enter / Apply ↵ / Browse), restart-on-commit, last-cwd persistence\n- [x] **Persist open tabs across restart** (id, title, agent, cwd)\n- [ ] Transcript snapshots (carry scrollback across restart)\n- [ ] `Cmd+T` / `Cmd+Shift+T` keyboard shortcuts\n\n### v0.3.0 — Providers UI + Gateway ✅\n- [x] CRUD UI for provider profiles (sidebar list + \"+ Add provider\" picker, default-expanded)\n- [x] Built-in templates for **28 vendors** (OpenClaw mirror): DeepSeek, OpenAI, Anthropic, Google Gemini, xAI, Groq, Mistral, Moonshot, Cerebras, Together, Fireworks, Z.AI, Qwen, Volcengine, MiniMax, StepFun, OpenRouter, NVIDIA NIM, Hugging Face, Perplexity, Amazon Bedrock, SGLang, vLLM, Ollama, LM Studio, Vercel AI Gateway, LiteLLM, Custom\n- [x] Dual base-URL selector (OpenAI-compatible vs Anthropic-compatible) for **every** provider\n- [x] Latest-models dropdown per provider (freeform input still allowed)\n- [x] Per-agent provider binding + per-agent model override (CLI flag projection — Codex / Claude / OpenCode honour Tday's model setting)\n- [x] \"Use one provider/model for all agents\" shared-config toggle\n- [x] **DeepSeek Anthropic gateway proxy** — in-process HTTP server translating OpenAI Responses API → Anthropic Messages API; supports streaming, extended thinking, tool use, multi-turn (113 unit tests, 12 modules)\n- [ ] Secrets via Rust `keyring` crate (currently plaintext `~/.tday/providers.json`)\n- [ ] Per-tab provider override + \"last-used\" memory\n\n### v0.4.0 — Local-inference autodetect\n- [ ] Rust scanner: TCP probe + HTTP fingerprint\n  - Ollama: `GET /api/tags`\n  - LM Studio: `GET /v1/models` (port 1234)\n  - llama.cpp: `GET /v1/models` (port 8080)\n  - vLLM: `GET /v1/models` (port 8000)\n- [ ] mDNS discovery for LAN servers\n- [ ] Toast “Found Ollama with 7 models — add as provider?”\n- [ ] Watch loop with backoff\n\n### v0.5.0 — Token usage analytics\n- [ ] SQLite schema: `usage(ts, tab_id, agent, provider, model, prompt_tok, completion_tok, cost_usd)`\n- [ ] Adapter `parseUsage()` hooks\n- [ ] Dashboard: stacked-area + table + filters\n- [ ] CSV/JSON export\n\n### v0.6.0 — Unified long-term memory\n- [ ] `sqlite-vec` embedding store\n- [ ] Embed-on-write background worker (Rust)\n- [ ] MCP server `tday-memory` exposing `recall`, `remember`, `forget` to any agent\n- [ ] Per-project + global scopes\n- [ ] UI to browse, edit, prune memories\n\n### v0.7.0 — Performance \u0026 polish\n- [ ] xterm WebGL renderer; benchmark vs canvas\n- [ ] Lazy-render inactive tabs\n- [ ] Session snapshot/restore\n- [ ] Memory budget per tab; warn on leak\n- [ ] Profiling page (CPU/RSS/handles)\n\n### v0.8.0+ — see Roadmap table\n\n---\n\n## 5. Repository Layout\n\n```\ntday/\n├── apps/\n│   └── desktop/                  # Electron app (main + preload + renderer)\n│       ├── src/main/             # main process\n│       ├── src/preload/          # contextBridge\n│       ├── src/renderer/         # React app\n│       ├── electron.vite.config.ts\n│       └── package.json\n├── packages/\n│   ├── shared/                   # shared types (IPC contracts, AgentAdapter, …)\n│   ├── adapters/\n│   │   ├── pi/                   # v0.1.0\n│   │   ├── claude-code/          # v0.2.0\n│   │   ├── codex/                # v0.2.0\n│   │   └── opencode/             # v0.2.0\n│   └── ui/                       # shared components (border-beam, …)\n├── crates/\n│   └── tday-core/             # Rust binary (detect, tokens, memory)\n├── pnpm-workspace.yaml\n├── package.json\n└── README.md\n```\n\n---\n\n## 6. Quickstart\n\n```bash\n# prerequisites\nnode -v        # ≥ 20\npnpm -v        # ≥ 9\nrustc --version  # ≥ 1.78\n\n# install + run\npnpm install\npnpm build:core      # builds tday-core (Rust)\npnpm dev             # launches the desktop app\n\n# point Tday at your `pi` binary if it isn't on PATH\necho '{ \"agents\": { \"pi\": { \"bin\": \"/absolute/path/to/pi\" } } }' \\\n  \u003e ~/.tday/agents.json\n```\n\nThe first window opens with a single tab running `pi` inside a real PTY.\n\n---\n\n## 7. Build and Release\n\n### Local build\n\n```bash\n# typecheck the workspace\npnpm -r typecheck\n\n# build the desktop app\npnpm --filter @tday/desktop build\n\n# create macOS packages locally (.dmg + .zip for x64 and arm64)\npnpm --filter @tday/desktop package:mac\n\n# create Windows and Linux packages locally on their native hosts\npnpm --filter @tday/desktop package:win\npnpm --filter @tday/desktop package:linux\n```\n\nLocal packaging writes artifacts to `apps/desktop/release/\u003cversion\u003e/`.\nThose generated files are ignored by git and are not meant to be committed.\n\n### GitHub Actions\n\nThe repository ships with `.github/workflows/release.yml`.\n\n- Push to `main`: builds macOS (`x64`, `arm64`), Windows (`x64`), and Linux (`x64`) packages on GitHub Actions and uploads them as workflow artifacts.\n- Push a tag like `v0.1.12`: builds the same cross-platform artifacts and publishes them to a GitHub Release automatically.\n- Run the workflow manually: builds artifacts on demand; if `publish` is enabled, it creates a draft GitHub Release.\n\nThe CI packaging step uses `electron-builder --publish never`, so the build pipeline uploads release assets to GitHub Releases only and does not push packaged binaries back to the repository.\n\n### Recommended release flow\n\n```bash\n# 1. commit your code changes\ngit push origin main\n\n# 2. create a version tag to trigger a GitHub Release\ngit tag v0.1.12\ngit push origin v0.1.12\n```\n\n---\n\n## 8. Design principles\n\n1. **Native where it matters.** PTY, tokenization, memory, scanners — all in Rust or `node-pty`. Electron is the chrome, never the bottleneck.\n2. **Adapter-first.** Adding a new harness must be ≤ 100 LOC.\n3. **Provider-agnostic.** No harness should be locked to a vendor; we own env injection.\n4. **Local-first.** Everything works offline with Ollama/LM Studio/llama.cpp/vLLM.\n5. **Don’t hide the terminal.** It’s a terminal. Keystrokes, escape codes, colors, mouse — all forwarded faithfully.\n\n---\n\n## 9. License\n\nMIT License\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funbug%2Ftday","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funbug%2Ftday","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funbug%2Ftday/lists"}