DEV Community

Cover image for One Developer + One AI Bot: Building an SSH Client in 45 Self-Iterating Rounds
Shuaipeng Guo
Shuaipeng Guo

Posted on

One Developer + One AI Bot: Building an SSH Client in 45 Self-Iterating Rounds

AI-SSH-Pro: one developer + one AI bot, 45 self-iterating rounds

I'm building AI-SSH-Pro, an open-source SSH client with a built-in AI assistant (Electron + React + TypeScript): terminal, SFTP, command history and AI chat in one window.

The unusual part is the team. It's me plus one AI bot. I treat the bot as a whole product team — product manager, UX/UI designer, developer, QA, and retro lead — and let it iterate round after round on its own. My job is direction, feedback, and deciding when to ship.

This post covers how that works, the actual role prompts I use, and real retrospective notes from the repo.

The numbers

All of these come straight from git log and the docs folder, as of 2026-10-21:

  • 405 commits in total (first commit on 2026-04-02), 319 of them in just two days (Oct 20–21).
  • 45 rounds of continuous self-iteration completed since Oct 20; round 46 is in progress.
  • 124 design docs under docs/iterations/.
  • 407 regression tests, all green on the latest full npm test run.
  • 11 retro entries in docs/retro.md, distilled into 17 rules in docs/dev-rules.md.

The loop: one bot, five hats

Every round follows the same pipeline:

Product → UX/UI design → Development → QA → Retro

  • Product proposes just 3 small items per round, focused on what people use every day: connecting, the terminal, SFTP, history, AI chat.
  • Design screenshots the real UI first, then writes a design doc.
  • Development commits in small steps — one item, one commit.
  • QA adds regression tests; nothing is done until the full suite passes.
  • Retro turns every mistake into an actionable rule that the next round reads first.

A round takes roughly 30 minutes. Any bug I report jumps the queue.

The role prompts

These are the prompts I actually use, lightly trimmed. Feel free to copy them.

Shared context (always first)

Project: AI-SSH-Pro, an AI SSH client (Electron + React + TypeScript).
Rules: commit locally only; push only for releases. npm test must be fully green.
Use theme components and spacing tokens, never native <select>.
Production hosts show a banner but are not blocked; read-only hosts block writes.
AI-generated commands are only prefilled — the user presses send.
Redact anything before it is sent to the AI.
Enter fullscreen mode Exit fullscreen mode

Product

You are the product manager. Only propose high-frequency, everyday features;
niche ideas go to the backlog. Before proposing, grep docs/iterations and src
to dedupe — never re-propose something already built.
Each round: 3 small items, each with the user scenario, what feels awkward today,
and the change the user will actually notice.
Enter fullscreen mode Exit fullscreen mode

UX / UI design

You are the UX/UI designer. Screenshot the real UI first, then write a design doc.
Cover empty, disabled (explain why) and error states, shortcuts, and both
light and dark themes. Principles: dense but not cramped, symmetric layouts,
icon buttons over text buttons, and never drop an existing feature.
Enter fullscreen mode Exit fullscreen mode

Development

You are the developer. Implement the design doc in small steps, one commit per item,
no pushing. Toggle-style state must read the latest value from a ref.
Render popovers into document.body so they never get clipped.
Enter fullscreen mode Exit fullscreen mode

QA

You are QA. Every item gets a regression test covering rapid repeated clicks,
acting after switching tabs, and edge cases. Run the full npm test on the final
HEAD — it must be all green. Capture before/after screenshots.
Enter fullscreen mode Exit fullscreen mode

Retro

You are the retro lead. After every round and every bug fix, append an entry to
docs/retro.md: time (planned vs actual), where it got stuck, what went wrong,
root cause, and how to avoid it next time (as an actionable rule).
Promote general rules to docs/dev-rules.md. Read them before each round starts.
Enter fullscreen mode Exit fullscreen mode

Self-iteration (one line to start it)

Iterate continuously: product → design → dev → QA → retro, round after round,
without asking me. ~30 minutes per round; bugs I report jump the queue.
End each round with a 3–5 line report.
Enter fullscreen mode Exit fullscreen mode

Quick request / bug (the one I use most)

[screenshot] This doesn't respond / this looks messy — designers, please fix it.
State the root cause or design rationale first, then fix, test, commit, and write a retro entry.
Enter fullscreen mode Exit fullscreen mode

Before and after

Split view: from a dedicated toolbar to pane headers

The old split toolbar ate a whole row, used a native dropdown, and had a cryptic "left/right" button. Now the controls live in each pane's header, primary and secondary panes are clearly labeled, and broadcast input is a real toggle.

Split view before and after

The split button in the top-right became a menu: off, side-by-side, or stacked, with the current mode checked.

Split mode menu

Snippets: one line each, built-ins grew from 3 to 26

Each snippet used to be a tall card. Now it's a single row, action buttons appear on hover, and double-click or Enter only prefills the command — it never runs it. Risky commands like delete or reboot are deliberately left out of the built-in list.

Snippets panel before and after

SFTP header: it started with one screenshot

This is the screenshot I sent the bot: the breadcrumb duplicated the path input, the two sides didn't match, and too many text buttons wrapped onto a second line. The bot came back with a design and shipped it: one symmetric row per side, click the address bar (or press Ctrl+L) to type a path, and rarely used actions tucked into a "More" menu.

My feedback screenshot of the old SFTP header

AI chat panel

AI chat panel

Real retros

Each of these is taken from docs/retro.md and matches a real incident.

1. "The split button doesn't respond"

  • What I saw: the split toggle worked only sometimes; clicking it again after enabling often did nothing.
  • Root cause: a missing useCallback dependency meant the closure read stale state. Tests only covered a single click.
  • Rule: toggle callbacks that fire repeatedly always read the latest value from a ref. Toggle tests must cover two clicks in a row, three rapid clicks, and acting after switching tabs.

2. The split redesign took an hour

  • What I saw: a 30-minute task took about 60.
  • Root cause: the requirements changed mid-way with no new estimate; the full test suite ran after every small edit; the screenshot script kept turning split view off.
  • Rule: run only related tests while iterating and the full suite once on the final HEAD; re-estimate before acting on a requirement change; screenshot scenarios must be idempotent.

3. A wall of script after connecting to a server

  • What I saw: connecting to a test server echoed the shell-integration bootstrap script into the terminal.
  • Root cause: it was only verified on the demo host, which has no real TTY, so the echo was invisible.
  • Rule: anything written into a remote shell must be checked once in a real interactive bash session for echo and history. Anything meant to be hidden needs an explicit end marker and a render-layer gate.

4. "All tabs" flashes and disappears

  • What I saw: clicking "All tabs" showed the list for a split second.
  • Root cause: the auto-close condition was "close when tabs don't overflow", but the button had since been made always visible — the condition was never updated.
  • Rule: popovers may auto-close only on a state transition, never on the current state; when changing an entry point's visibility, grep every effect on that state; every popover needs a "stays open after opening" test.

5. Product kept re-proposing finished features

  • What I saw: the product role repeatedly suggested things that already existed.
  • Root cause: different wording from the existing implementation, and dedupe relied on memory.
  • Rule: every proposal must grep docs/iterations, the backlog and src with at least two synonyms, and list the search terms and hits in the proposal.

6. A context menu covering a modal

  • What I saw: the tab context menu stayed on top of the host-key dialog.
  • Root cause: the fix assumed all menus shared one close path, but the tab menu had its own state in App.
  • Rule: before touching popover behavior, grep every popover implementation and list its owner; closing goes through a single broadcast event that every menu must listen to; layering fixes must be verified with an "after" screenshot.

What the human actually does

In this setup I do three things:

  • Direction: decide where the product goes — for example, "only build high-usage features".
  • Feedback: use the app, take a screenshot, and say "this is messy" or "this doesn't respond".
  • Release decisions: when to cut a test build and when to push is my call.

Breaking down requirements, design, code, tests and retros are all handled by the bot. The retro loop means each mistake is (ideally) made only once — the rulebook keeps growing, and iterations keep getting steadier.

Try it

Feedback is very welcome — and if you're also letting an AI drive your development, I'd love to hear how you run it.

Top comments (0)