Mockup 03 · ReferencePiyush's actual architecture
What Piyush Jha actually shipped in January 2026 — the first nine commits of IdeaFlowCo/cortex before Tejas DC rewrote everything onto Fly.io Docker containers. This page exists so nothing in the picortex planning docs overstates what's "from Piyush" vs. what's new.
1The nine commits
All by Piyush Jha <piyushjha8164@gmail.com>, 2026-01-20 through 2026-01-23. Final tip: d2d6a534. Replaced wholesale starting af3a76f5 (Tejas DC, 2026-01-26).
238052c4 2026-01-20 Initial commit: Initialize Cortex project with Beads
21a765f4 2026-01-20 Add all Cortex project tickets with dependencies
f43d1c25 2026-01-20 Implement complete Cortex cloud Claude CLI platform
424b15df 2026-01-20 Add EC2 infrastructure setup documentation and scripts
e6d1c738 2026-01-20 Fix SSH streaming and improve chat functionality
168eb7ae 2026-01-20 Remove tsc from build command for Vercel deployment
880ba248 2026-01-20 Add project documentation files
82327e54 2026-01-23 Add SSH key generation for direct workspace access
d2d6a534 2026-01-23 Update README.md
2The architecture
Three tiers. Not three picortex-style "machines" — it's Vercel (just a CDN for the static build) + a backend server somewhere + one EC2 box where every user has their own Linux account.
3The turn loop — literally his code
From backend/src/services/claudeService.ts at d2d6a534:
async executePrompt(username: string, prompt: string): Promise<ClaudeResult> {
const escapedPrompt = prompt.replace(/'/g, "'\\''").replace(/"/g, '\\"');
// -c continues the previous conversation session
// --dangerously-skip-permissions allows file operations without interactive prompts
const command = `claude -c --dangerously-skip-permissions -p "${escapedPrompt}"`;
const result = await sshService.execAsUser(username, command);
if (result.code !== 0) {
return { content: '', error: result.stderr || 'Claude CLI execution failed' };
}
return { content: result.stdout };
}
And the chat WebSocket handler in backend/src/websocket/handlers/chatHandler.ts:
socket.on('chat:message', async (data) => {
const workspace = await prisma.workspace.findUnique({ where: { userId } });
if (!workspace || workspace.status !== 'ready') return socket.emit('chat:error', ...);
await prisma.message.create({ data: { userId, role: 'user', content: data.content } });
socket.emit('chat:thinking', { status: true });
let fullResponse = '';
await claudeService.executePromptStreaming(workspace.linuxUsername, data.content, (chunk) => {
fullResponse += chunk;
socket.emit('chat:response', { content: chunk, done: false });
});
await prisma.message.create({ data: { userId, role: 'assistant', content: fullResponse } });
});
That's the whole engine. Per turn: pull the chat's Linux username, SSH in, run claude -c -p, stream stdout back through WebSocket, write the result to Prisma. No tmux, no sentinels, no queues. ~80 lines.
4Features (and the noticeable absences)
| What Piyush had | What he didn't |
|---|---|
| Signup + JWT auth; user brings own Anthropic key | No texting / iMessage / SMS surface at all |
| Per-user workspace provisioning over 4 WebSocket progress steps | No group chats; no multi-participant conversations |
| Web chat UI (single thread per user) | No attention gating — a web chatbot either responds or doesn't |
| File browser (ls / read / write) over SSH | No consent / approval loop — there's only one user per workspace |
| xterm.js web terminal with an SSH PTY | No knowledge graph — files and Claude's memory were the whole context |
OpenAI-based voice chat (voiceService.ts) |
No audit log beyond Message rows |
apiKeyHelper so workspaces never held plaintext keys |
No sharing / bridging between workspaces |
5What the No-Docker architecture borrows (and what it adds)
| Borrowed from Piyush | New in No-Docker |
|---|---|
| Split: bot server ≠ workspace host | Per-chat (not per-user) Linux accounts |
| SSH exec per turn, one command per turn | Attention gate (mentions-only, discriminator) |
claude -c -p pattern | Consent broker + out-of-band DM approvals (PRD 002 P4) |
Narrow sudoers scoped to useradd family only | noos knowledge graph on a third reused box |
| apiKeyHelper so workspace FS has no plaintext keys | Linq / OpenChat channel (no web chat in v0.1) |
| Mock SSH mode for dev | DisclosureEvent & ManifestEvent audit tables |
6Why his design was replaced
Cortex pivoted from "per-user web chat for one team" to a multi-tenant enterprise product. That pivot needed:
- Per-chat (not per-user) workspace isolation, so group texts could each have their own filesystem
- Container-strength tenant isolation as the product opened to outside paying users
- Linq / iMessage as a first-class surface, not the browser web chat
Tejas DC's af3a76f5 introduced Fly.io Docker containers per workspace; everything Piyush wrote was replaced in the process. For picortex-as-a-personal-tool, the pivot's justification doesn't apply — Piyush's simpler design is arguably the better starting point.
See also: docs/wiki/piyush-era-design.md (full text study) · Mockup 01 — what picortex actually proposes