
At 9 AM, before a single line of code is written, the System Analyst's calendar is already full.
I open:
Sound familiar?
The problem isn't the number of apps. It's the manual synchronization. One change in the FSD means I have to update the ERD in tab 3, the API Spec in tab 2, the tasks in tab 5, and copy-paste a prompt into tab 7. Miss one update and the delivery to developers is outdated.
In the industry this is called Tool Fatigue or Tab Hoarding Syndrome. Time that should be spent thinking is spent switching tabs and converting formats.
And that time is shrinking. Analysis used to get two weeks. Now it's 3-4 days with the same quality expectations.
I needed another way.
I tried the obvious solution: AI chatbots.
Helpful at first. But once the FSD hit 50+ pages, three problems kept recurring:
ChatGPT Team / Claude Cowork is $20-30 per seat per month. For a team of 5 SAs that's $100-150/month just for chat. Excluding API costs. For individuals or small teams in Indonesia, that's expensive.
This is the fatal one. I pasted FSD chapters 1-3, then had a long discussion about edge cases in chapter 5. Halfway through, the AI forgot the orders -> payments relationship we agreed on at the start. Or the business rule "refund only if status = PAID".
Once the chat gets long, AI loses context. I have to re-paste the document, repeat the prompt, and hope it remembers. That's not assistance, that's babysitting.
Browser AI doesn't know my file is at D:/projects/client-xyz/input/fsd. every analysis requires re-uploading, copy-pasting, or explaining folder structure. Developers work in a local repo. Why should SAs work in a separate cloud?
My conclusion: AI chatbots are chat buddies, not co-workers, I need AI that works on top of my files, not me working inside its chat.
The turning point was a simple question: what if all SA artifacts lived as files in one folder and every view was generated automatically from those files?
Answer: Markdown + DBML.
Why Markdown?
In Onesist the project structure is standardized:
<project-root>/
├── input/
│ ├── fsd/ # Raw FSD (PDF, DOCX, MD) — source of truth
│ └── figma/ # Design screenshots
└── output/
├── spec/ # API Spec (.md / openapi.yaml)
├── erd/ # DBML schema (.dbml)
├── task/ # Task cards per phase (<phase>/<task>.md)
├── sit/ # Test cases (.md)
├── sketches/ # Excalidraw (.excalidraw.json)
└── timeline.html # Gantt chart
From this single source, Onesist renders:
@dbml/core) then auto-laid out with Dagre + ReactFlow. Edit tables visually, export back to DBML/SQL.spec-parser.ts) into endpoint cards with search, payload viewer, and module grouping.task-parser.ts) into Kanban/List with story points, status, and phase grouping.Example DBML that powers the ERD:
Table orders {
id uuid [pk]
user_id uuid [ref: > users.id]
status varchar [note: "DRAFT | PAID | REFUNDED"]
total decimal
created_at timestamp
}
Table payments {
id uuid [pk]
order_id uuid [ref: > orders.id]
amount decimal
method varchar
}
Change 5 lines -> ERD canvas updates. AI changes the file -> frontend auto-refreshes via file watcher. No manual sync.
Living Artifacts: Files are the truth. UI is just a viewer.
This is what most distinguishes Onesist — and what gets screenshot the most.
Not a headless "Run" panel whose JSONL errors are hard to trace, but a real Agent Terminal inside the dashboard — a true PTY, not a chat simulation.

Instead of calling OpenAI/Anthropic APIs from the browser, Onesist opens a real terminal inside the dashboar where you run opencode run, claude -p, or codex exec in the actual project root. The agent works on your files, you watch it live.
Embedded Terminal (xterm.js) ← this is the highlight
│ PTY WebSocket src/server/terminal/terminal-server.ts
│ + xterm.js src/components/agent/AgentTerminal.tsx
▼
Agent CLI (opencode / claude / codex / agy) — cwd = projectRoot
│ reads/writes files
▼
input/fsd/ → output/erd/*.dbml, output/spec/*.md, output/task/*.md
│ file:changed
▼
Dashboard UI auto-refresh src/server/realtime/file-watcher.ts + SSE
Why the Terminal is the highlight, not the Runner?
agent-runner.ts (headless -format json) exists for automation but still has JSONL parsing edge cases. The Agent Terminal is stable and honest: a real PTY via node-pty (macOS/Linux) / ConPTY (Windows), streamed over Websocket, attach/detach without killing the session, and every log visible as-is just like opening a Terminal in VS Code.
Daily flow (what you see in the screenshot):
spawns an opencode session with cwd = projectRoot skills in .agents/skills/ (fsd-analyzer, markitdown, diagram-svg, query-writer) are auto-available.Use the fsd-analyzer skill. From FD1..FDn generate ERD to output/erd/schema.dbml like chat, but the agent does readFile/writeFile in input/ & output/.write streams in the terminal. Need to steer? Ctrl+C, type continue but don't touch MASTER_ERD.mdWhy this feels better because of the Terminal:
src/server/db/client.ts WAL mode + files on disk).readFile(root, relPath) (lib/file-router.ts) 200-page FSD? Read as files, not pasted into chat history.fsd-analyzer SkillAI without guardrails is like a smart but inventive junior frequent hallucinations: tables that don't exist in the FSD, or missing critical endpoints.
Onesist's solution: Skill System.
A skill is a rules of engagement a standard that binds AI to SA methodology instead of improvising.
Two core skills are bundled in vendor/skills/:
fsd-analyzer: for FSD, ERD, Spec, and Task completeness analysis.markitdown: for PDF/DOCX/PPTX -> Markdown conversion.On the frontend, the FSD Completeness Checker (lib/fsd-completeness.ts):
Example gap detection output:
[GAP] FSD Chapter 3.2 mentions "refund" but no refunds table in ERD
[GAP] Endpoint POST /orders/refund in Spec but no task in output/task/
[OK] All FSD entities have tables in ERD (12/12)
AI is no longer free to invent. It must pass the checklist before an artifact is considered final.
That's what makes AI consistent not long prompts, but standardization.
Here's how the end-to-end flow works in Onesist the 7-phase pipeline from docs/README.md:
Phase 1: FSD -> Markdown Upload PDF/DOCX to input/fsd/, run the markitdown prompt via embedded terminal -> markdown in input/fsd/. Then split per module (FD1, FD2...) via split prompt.
Phase 2: Discovery Discussion mode with the agent ask QUESTION_FOR_BA or ASSUMPTION for unclear FSD items. Iterate until aligned.
Phase 3: ERD Prompt generate ERD from FD1..FDn -> DBML in output/erd/. Open ERD Studio - ReactFlow canvas, drag tables, edit columns visually, export to SQL. Not final? Discuss and regenerate.
Phase 4: API Spec Prompt generate Spec + openapi.yaml from FD + ERD -> files in output/spec/. Open API Spec module navigation, endpoint search, payload view. Finalize here before tasks.
Phase 5: Tasks & Timeline Prompt generate Task Cards + Estimation + Timeline from ERD + Spec -> markdown per task in output/task/<phase>/ + output/timeline.html (Gantt). Open Tasks phase accordions, story points, bulk status updates.
Phase 6: Traceability (RTM) RTM tab maps BR -> FR -> DS -> TC Business Requirement to Test Case. AI gap detection flags requirements without tests.
Phase 7: Technical Documentation Prompt generate SRS from all artifacts -> DOCX/Markdown in output/docs/.
All tabs read the same files. Change a file on disk -> UI updates. No experimental "Sync to DB" button the file watcher does the work.




Why not just a web app?
Because SAs need a lightweight, fast, offline-first native workspace.
Stack choices:
| Layer | Technology | Why |
| Runtime | Bun 1.3+ | Fast, built-in SQLite, <1s startup |
| Framework | React 19 + Tanstack Start (SSR) | File-based routing, server functions |
| Desktop Shell | Tauri 2 (Rust) | 10x smaller memory footprint than Electron |
Desktop Architecture:
Tauri shell (Rust) ──spawn──▶ onesist-server (compiled Bun)
│ │
└── WebView ◀──http─── localhost:{PORT} (SSR + /api/*)src-tauri/src/sidecar.rs): SA_DB_PATH, SA_CLIENT_DIR, SA_MIGRATIONS_DIR, SA_ROOT, SA_VENDOR_SKILLS_DIR, SA_DESKTOP=1 (PPID watchdog). All absolute macOS GUI launch has CWD=/, so process.cwd() breaks.Why not Electron? Memory & startup. Tauri uses the OS native WebView (WebKit on macOS, WebView2 on Windows) no bundled 150MB Chromium. Result: smaller installer, ~300MB idle RAM (vs 800MB+ Electron), and signed auto-updates via @tauri-apps/plugin-updater.
Real results after using Onesist:
Biggest lessons:
fsd-analyzer skill beats 100 creative but inconsistent ad-hoc prompts.The future System Analyst won't be replaced by AI but SAs who use AI will replace those who don't.
Onesist is my attempt to make that transition reduce tool fatigue, not increase it.
bun install && bun run dev → open http://localhost:4321 → Open Project → select folder with input/ & output/docs/README.md — 7-phase pipeline + prompt library + best practicesbunx tauri dev (requires Rust toolchain)writes output/erd/schema.dbml, file-watcher.ts -> file:changed -> ERD tab auto-refreshes. Files on disk are the state.opencode -> claude -> codex -> agy. Same workflow & prompts, same cwd & skills.| UI |
| Kumo + Tailwind 4 |
| Enterprise-ready design system |
| Editor | MDXEditor + CodeMirror 6 | Markdown + code editing |
| Diagrams | Mermaid 11, DBML, Excalidraw | Direct artifact rendering |
| DB | SQLite WAL + Drizzle ORM | Local, WAL checkpoint, no server |
| Terminal | xterm.js + WebSocket | Embedded agent terminal |
mark_quitting() + std:process::exit(0) after 150ms (avoid macOS app.exit() hang) Memory watchdog: sidecar 3000MB, WebView 6000MB.bun run build:server -> Vite build -> terminal bundle -> scripts/post-build.mjs -> compile onesist-server binary to src-tauri/binaries/.