-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocs.html
More file actions
1804 lines (1736 loc) · 120 KB
/
docs.html
File metadata and controls
1804 lines (1736 loc) · 120 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Termpolis Documentation — Secure AI-Assisted Development</title>
<meta
name="description"
content="Complete guide to Termpolis: AI Security Center (pre-paste secret scanner, Gemini paid-tier enforcement, audit log), copy-for-Slack/Teams output, multi-agent swarm orchestration, MCP server, shared memory, and live observability."
>
<meta name="author" content="Termpolis">
<link rel="canonical" href="https://termpolis.com/docs.html">
<link rel="icon" type="image/svg+xml" href="logo-termpolis-titlebar.svg">
<link rel="shortcut icon" href="logo-termpolis-titlebar.svg">
<!-- Open Graph -->
<meta property="og:type" content="article">
<meta property="og:site_name" content="Termpolis">
<meta property="og:url" content="https://termpolis.com/docs.html">
<meta property="og:title" content="Termpolis Documentation — Secure AI-Assisted Development">
<meta property="og:description" content="Every feature, panel, and keyboard shortcut in Termpolis — the terminal where Claude, Codex, Gemini, and Qwen work as a team.">
<meta property="og:image" content="https://termpolis.com/assets/screenshot-welcome.png">
<meta property="og:image:width" content="1368">
<meta property="og:image:height" content="908">
<meta property="og:image:alt" content="Termpolis welcome screen with AI agents, workspaces, and swarm controls.">
<meta property="og:locale" content="en_US">
<!-- Twitter / X -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Termpolis Documentation — Multi-Agent AI Terminal Guide">
<meta name="twitter:description" content="Every feature, panel, and shortcut in the AI terminal where Claude, Codex, Gemini, and Qwen work as a team.">
<meta name="twitter:image" content="https://termpolis.com/assets/screenshot-welcome.png">
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="docs.css">
<!-- Cloudflare Web Analytics -->
<script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "69e1842746294b5bbb72378c748cb522"}'></script>
<!-- End Cloudflare Web Analytics -->
</head>
<body class="docs-body">
<div class="docs-shell">
<header class="docs-header">
<a class="brand" href="index.html" aria-label="Termpolis home">
<img class="brand-logo" src="logo-termpolis.svg" alt="Termpolis logo">
<span class="brand-text">Termpolis</span>
</a>
<nav class="site-nav" aria-label="Primary">
<a href="index.html#security">Security</a>
<a href="index.html#swarm">Smart Swarm</a>
<a href="index.html#observability">Observability</a>
<a href="index.html#share">Share to Slack/Teams</a>
<a href="index.html#features">Features</a>
<a href="index.html#downloads">Downloads</a>
<a href="docs.html" aria-current="page" class="active">Docs</a>
</nav>
<div class="docs-search">
<input
id="docs-search-input"
type="search"
placeholder="Search docs…"
aria-label="Search documentation"
autocomplete="off"
>
</div>
</header>
<div class="docs-layout">
<aside class="docs-sidebar" aria-label="Documentation sections">
<div class="docs-sidebar-inner">
<p class="docs-sidebar-eyebrow">Get started</p>
<ul class="docs-toc">
<li><a href="#overview" class="docs-toc-link">Overview</a></li>
<li><a href="#install">Installation</a></li>
<li><a href="#install-windows-defender" class="docs-toc-sub">↳ Windows Defender FP recovery</a></li>
<li><a href="#api-keys">Before you begin · API keys</a></li>
<li><a href="#first-launch">First launch (5 steps)</a></li>
<li><a href="#first-agent">Launch your first AI agent</a></li>
<li><a href="#swarm-vs-single">Swarm vs. single agent</a></li>
</ul>
<p class="docs-sidebar-eyebrow">🛡 Security</p>
<ul class="docs-toc">
<li><a href="#security-center">AI Security Center</a></li>
<li><a href="#security-secret-scanner">Pre-paste secret scanner</a></li>
<li><a href="#security-sensitive-file">Sensitive-file-read alert</a></li>
<li><a href="#security-codechunk">Code-chunk + env-dump heuristics</a></li>
<li><a href="#security-egress">Per-agent egress audit</a></li>
<li><a href="#security-tos-drift">ToS drift watcher</a></li>
<li><a href="#security-gemini">Gemini account-mode + Strict Mode</a></li>
<li><a href="#security-audit">Audit log</a></li>
<li><a href="#security-disclaimer">Legal disclaimer</a></li>
</ul>
<p class="docs-sidebar-eyebrow">Share output</p>
<ul class="docs-toc">
<li><a href="#copy-share">Copy for Slack / Teams / PRs</a></li>
</ul>
<p class="docs-sidebar-eyebrow">Core terminal</p>
<ul class="docs-toc">
<li><a href="#sidebar">Sidebar</a></li>
<li><a href="#workspaces">Workspaces</a></li>
<li><a href="#terminals">Terminals</a></li>
<li><a href="#views">Tabs, splits & grid</a></li>
<li><a href="#settings">Settings</a></li>
<li><a href="#themes">Themes</a></li>
<li><a href="#keybindings">Keybindings</a></li>
</ul>
<p class="docs-sidebar-eyebrow">Productivity</p>
<ul class="docs-toc">
<li><a href="#command-palette">Command palette</a></li>
<li><a href="#prompt-templates">Prompt templates</a></li>
<li><a href="#workflows">Workflow templates</a></li>
<li><a href="#context">Context panel</a></li>
<li><a href="#context-handoff">Cross-AI context handoff</a></li>
<li><a href="#history">History search</a></li>
<li><a href="#conversation">Conversation search</a></li>
<li><a href="#git">Git panel</a></li>
</ul>
<p class="docs-sidebar-eyebrow">AI & swarm</p>
<ul class="docs-toc">
<li><a href="#agents">AI agent profiles</a></li>
<li><a href="#capabilities">Capability ratings</a></li>
<li><a href="#mcp">MCP server</a></li>
<li><a href="#swarm">Swarm dashboard</a></li>
<li><a href="#conductor">AI conductor</a></li>
<li><a href="#activity">Activity feed</a></li>
<li><a href="#intervention">Intervention controls</a></li>
<li><a href="#review">Swarm review</a></li>
<li><a href="#memory">Shared memory</a></li>
<li><a href="#observability-docs">Observability</a></li>
</ul>
<p class="docs-sidebar-eyebrow">Reference</p>
<ul class="docs-toc">
<li><a href="#status-bar">Status bar</a></li>
<li><a href="#shortcuts">Keyboard shortcuts</a></li>
<li><a href="#architecture">Architecture</a></li>
<li><a href="#troubleshooting">Troubleshooting</a></li>
</ul>
<p class="docs-sidebar-eyebrow">Help us improve</p>
<ul class="docs-toc docs-toc-external">
<li>
<a
class="docs-sidebar-bug"
href="https://github.com/codedev-david/termpolis/issues/new?template=bug_report.md"
target="_blank"
rel="noreferrer"
>🐛 Report a bug</a>
</li>
<li>
<a
href="https://github.com/codedev-david/termpolis/issues/new?template=feature_request.md"
target="_blank"
rel="noreferrer"
>✨ Request a feature</a>
</li>
<li>
<a
href="https://github.com/codedev-david/termpolis/issues"
target="_blank"
rel="noreferrer"
>💬 Browse all issues ↗</a>
</li>
</ul>
</div>
</aside>
<main class="docs-content" id="docs-content">
<article>
<header class="docs-hero">
<p class="eyebrow">Documentation</p>
<h1>Termpolis Docs</h1>
<p class="docs-lead">
The definitive guide to Termpolis — <strong>Secure AI-Assisted Development</strong>.
The local-first multi-agent terminal where Claude, Codex, Gemini, and Qwen work as a
team without your source code leaving the machine. Built-in
<a href="#security-center">AI Security Center</a>, swarm orchestration, MCP server,
and a one-shortcut path from terminal to Slack, Teams, or a PR.
Every feature, every panel, every shortcut.
</p>
<p class="docs-hero-actions">
<a
class="docs-bug-btn"
href="https://github.com/codedev-david/termpolis/issues/new?template=bug_report.md"
target="_blank"
rel="noreferrer"
>🐛 Submit a bug report</a>
<a
class="docs-feature-btn"
href="https://github.com/codedev-david/termpolis/issues/new?template=feature_request.md"
target="_blank"
rel="noreferrer"
>✨ Request a feature</a>
</p>
</header>
<!-- OVERVIEW -->
<section id="overview" class="docs-section">
<h2>Overview</h2>
<figure class="docs-shot">
<img src="docs/screenshots/01-welcome-screen.png" alt="Termpolis welcome screen with AI agents and swarm.">
<figcaption>The welcome screen, where new sessions begin.</figcaption>
</figure>
<p>
Termpolis is a cross-platform desktop terminal manager (Windows, macOS, Linux) built on
Electron + React + TypeScript with <code>node-pty</code> powering the underlying shells.
It ships as a native app, code signed on Windows, notarized on macOS.
</p>
<p><strong>What makes it different:</strong></p>
<ul class="docs-list">
<li><strong>Secure AI-assisted development.</strong> Built-in <a href="#security-center">AI Security Center</a> auto-scans every AI prompt against 70+ secret patterns, enforces Gemini paid-tier mode, and keeps an auditable JSONL log of every AI-agent terminal launch — every check runs locally.</li>
<li><strong>Multi-agent swarm.</strong> Claude Code, Codex, Gemini CLI, and Qwen Code work together on a task. A dedicated Claude Code instance acts as the conductor.</li>
<li><strong>MCP server baked in.</strong> AI agents control Termpolis via Model Context Protocol, open terminals, run commands, send messages.</li>
<li><strong>Transparent routing.</strong> Every subtask shows which agent got it, why, and what it cost.</li>
<li><strong>Activity observability.</strong> Every token, every tool call, every message from every agent is visible in real time.</li>
<li><strong>Intervention controls.</strong> Pause, cancel, or steer any agent mid-task without leaving the feed.</li>
<li><strong>Shared memory.</strong> A RAG-backed memory store that any agent can read and write via MCP.</li>
<li><strong>MCP-native end to end.</strong> All four agents speak MCP — no terminal-output parsers, no glue scripts, no bridge code paths.</li>
<li><strong>Share-ready output.</strong> One shortcut from terminal to Slack, Teams, or a PR — see <a href="#copy-share">Copy for Slack / Teams / PRs</a>.</li>
</ul>
</section>
<!-- AI SECURITY CENTER -->
<section id="security-center" class="docs-section">
<h2>🛡 AI Security Center</h2>
<p>
Termpolis ships an in-app AI Security Center at <strong>Settings → Security</strong>.
Its goal is to give administrators visibility and layered controls around outbound
AI traffic so a team can adopt Claude Code, Codex, Gemini CLI, and Qwen Code with
the obvious accidents caught and a verifiable record of what was sent — knowing
that no in-the-loop tool can guarantee a hosted-model prompt never reaches the
provider.
</p>
<p>
<strong>What it is and isn't.</strong> Any tool that lets you talk to a hosted model
is, by definition, sending your prompt to that provider. Termpolis cannot air-gap
a prompt you choose to send and cannot guarantee a provider's stated retention
policy is enforced server-side. The Security Center is <em>defense in depth</em> —
it catches recognisable secrets, flags oversize code/<code>.env</code> pastes,
detects unexpected network endpoints, and writes everything to a local audit log.
For absolute air-gap, run a local model and accept the quality / hardware
trade-off.
</p>
<p><strong>Design principles:</strong></p>
<ul class="docs-list">
<li><strong>Local-first.</strong> Every check runs on the machine. None of these features send data to Termpolis or any third party.</li>
<li><strong>Native, not a browser/IDE plugin.</strong> Termpolis is a terminal manager, not a Chrome extension piping your buffer to a SaaS backend.</li>
<li><strong>No telemetry.</strong> No login, no phone-home. Optional crash reporting is opt-in and redacts user-folder paths first.</li>
<li><strong>Verifiable.</strong> Every claim links to the provider's published ToS page; a weekly drift watcher (v1.11.52) opens a tracking issue when those pages change.</li>
<li><strong>Honest about limits.</strong> Each control below names what it can <em>not</em> catch.</li>
</ul>
<h3>Per-provider training-disposition facts</h3>
<p>
The panel summarizes how each provider treats prompts on their commercial tier, sourced
from the official ToS pages and updated with each release of Termpolis:
</p>
<ul class="docs-list">
<li><strong>Anthropic (Claude Code).</strong> API + commercial usage — default off for training.</li>
<li><strong>OpenAI (Codex).</strong> API platform — default off for training.</li>
<li><strong>Google (Gemini CLI).</strong> Paid tier (API key, Vertex AI, Code Assist) — excluded from training. Free OAuth tier — Google may use prompts to improve products. Flagged yellow.</li>
<li><strong>Alibaba (Qwen Code).</strong> Paid DashScope — excluded from training. Local Ollama mode — prompts stay on your machine instead of going to any provider.</li>
</ul>
<h3 id="security-secret-scanner">Auto-scan every prompt (v1.11.44+)</h3>
<p>
Once you launch <code>claude</code>, <code>codex</code>, <code>gemini</code>, or
<code>qwen</code> in a terminal, every Enter and every paste-sized chunk
(≥32 bytes) is scanned in main-process memory against 70+ regex rules
<strong>before it reaches the PTY</strong>. Hits are redacted in place, audited
as <code>redaction_hit</code> events, and surfaced via a dismissable banner.
Non-AI terminals are not scanned (zero overhead). Coverage spans:
</p>
<ul class="docs-list">
<li>AWS (access keys <code>AKIA…</code>/<code>ASIA…</code>, secrets, session tokens).</li>
<li>GitHub (PAT <code>ghp_…</code>, fine-grained <code>github_pat_…</code>, OAuth secrets, runner tokens), GitLab, Bitbucket.</li>
<li>Azure (Storage AccountKey, SAS signature, connection strings, AD client secret, DevOps PAT) and GCP (service-account JSON, OAuth client ID).</li>
<li>AI providers: OpenAI, Anthropic, Google, HuggingFace, Cohere, Replicate.</li>
<li>Payments (Stripe, PayPal Braintree, Square), comms (Slack, Discord, Telegram, Twilio, SendGrid, Mailgun, Mailchimp, Postmark).</li>
<li>Cloud (Cloudflare, DigitalOcean, Heroku, Netlify, Vercel, Fly.io, Render, Pulumi), CI/CD (CircleCI, Travis, Codecov).</li>
<li>Observability (Sentry DSN, Datadog, New Relic, Rollbar, Honeycomb, Mapbox, Okta, Auth0).</li>
<li>Project mgmt (Linear, Notion, Asana, Jira, Figma), package registries (npm, PyPI, Docker Hub).</li>
<li>Secrets vaults (HashiCorp Vault, Doppler, 1Password Connect), DB connection strings (Postgres/MySQL/MongoDB/Redis), HTTP basic-auth URLs.</li>
<li>JWT, PEM/GPG private key blocks, and the <code>.env</code>-style catch-all (<code>SECRET_KEY=…</code>).</li>
</ul>
<p>
A manual paste-and-scan box also lives in Settings → Security for one-off checks
of clipboard text before pasting elsewhere.
</p>
<p>
Hits return a redacted preview so you can decide whether the prompt is safe to send.
The redaction scanner targets high-confidence patterns to keep false-positive rates
low — it is <strong>not</strong> a comprehensive DLP solution. Custom corporate
tokens may not be detected and must be vetted separately.
</p>
<h3 id="security-gemini">Gemini account-mode auto-detect + Strict Mode</h3>
<p>
The Gemini CLI is the highest-risk surface, because the free OAuth tier may be used
for product improvement. Termpolis inspects the running shell environment to identify
which tier the CLI will hit:
</p>
<ul class="docs-list">
<li><strong>Vertex AI</strong> — <code>GOOGLE_APPLICATION_CREDENTIALS</code> + <code>GOOGLE_CLOUD_PROJECT</code>.</li>
<li><strong>Code Assist (Workspace)</strong> — <code>GOOGLE_GENAI_USE_GCA=true</code>.</li>
<li><strong>Paid API key</strong> — <code>GEMINI_API_KEY</code> or <code>GOOGLE_API_KEY</code>.</li>
<li><strong>Free OAuth fallback</strong> — none of the above. Flagged in red.</li>
</ul>
<p>
When <strong>Strict Mode</strong> is enabled, Termpolis intercepts <code>gemini</code>
invocations from any terminal. If the resolved account mode isn't paid-tier-safe, the
launch is cancelled with <kbd>Ctrl+C</kbd> and an in-band ANSI banner explains why.
The blocked launch is recorded in the audit log as <em>BLOCKED: strict-mode + free-tier</em>.
Strict Mode only intercepts shell-level invocations of the <code>gemini</code> binary —
it does not block out-of-band paths (a renamed binary, a script that calls the Google
API directly, etc.). It is a tripwire for the common-case mistake, not a full proxy.
</p>
<h3 id="security-audit">Local JSONL audit log</h3>
<p>
Every AI-agent terminal launch can be recorded in <code>ai-security-audit.jsonl</code>
inside the userData directory. Each record is one JSON object containing the timestamp,
the agent, the terminal id, and (optionally) byte counts and hit counts. The file is
append-only with 10 MB rotation. It can be wiped from Settings → Security at any time.
The audit log captures only what Termpolis observes locally — activity that bypasses
Termpolis (a Gemini CLI run from a separate native terminal window, for example) is
not visible to the audit log.
</p>
<h3 id="security-sensitive-file">Sensitive-file-read alert (v1.11.53)</h3>
<p>
The pre-send secret scanner can only see what <em>you</em> type. When the AI
agent autonomously decides to read a sensitive file via its own
<code>Read</code> tool (or runs <code>cat</code>/<code>head</code>/<code>grep</code>
on one through <code>Bash</code>), the file's bytes have already been added to
the agent's context and transmitted to the provider on the next turn. The
terminal-side scanner never sees that path. This watcher closes the gap.
</p>
<p>
<strong>How it works.</strong>
<code>src/main/sensitiveFileWatcher.ts</code> subscribes to
<code>agentEventBus</code> <code>tool_call</code> events emitted by the
transcript watchers (Claude Code / Codex / Gemini). For each event it inspects
the tool name and arguments:
</p>
<ul>
<li>Filesystem-style tools (<code>Read</code>, <code>Edit</code>,
<code>Write</code>, <code>read_file</code>, <code>view</code>, …) →
pulls <code>file_path</code> / <code>path</code> / <code>filename</code> from the input.</li>
<li>Shell-style tools (<code>Bash</code>, <code>run_shell_command</code>,
<code>container.exec</code>, …) → tokenises the command, splits on
<code>&&</code>/<code>;</code>/<code>|</code>, and identifies positional
arguments to <code>cat</code>/<code>head</code>/<code>tail</code>/<code>grep</code>/<code>cp</code>/<code>curl -F file=@</code> and 15 other reader commands.</li>
</ul>
<p>
Each candidate path is matched against a hand-curated rule list:
<code>.env</code>/<code>.env.local</code>/<code>.env.production</code>
(excluding <code>.env.example</code>/<code>.sample</code>/<code>.template</code>);
<code>*.pem</code>/<code>*.key</code>/<code>*.p12</code>/<code>*.pfx</code>/<code>*.jks</code>/<code>*.keystore</code>;
<code>id_rsa</code>/<code>id_ed25519</code>/<code>id_ecdsa</code>/<code>id_dsa</code> (excluding <code>.pub</code>);
<code>~/.aws/credentials</code> + <code>~/.aws/config</code>;
GCP service-account JSONs;
files under <code>~/.ssh/</code> excluding <code>known_hosts</code>/<code>config</code>/<code>*.pub</code>;
<code>.netrc</code>/<code>.npmrc</code>/<code>.pypirc</code>;
<code>~/.docker/config.json</code>; <code>~/.kube/config</code> + <code>*.kubeconfig</code>;
<code>secrets.{yml,yaml,json,env,toml,ini}</code>; <code>credentials.{yml,json,…}</code>;
<code>*.kdbx</code>/<code>*.kdb</code> (KeePass);
and Chrome/Firefox/Edge cookie databases.
</p>
<p>
On a match the watcher writes an audit entry tagged
<code>sensitive_file_read</code> (with rule id, tool name, source path) and
fires a <code>terminal:sensitive-file-read</code> IPC event to the renderer
which displays a banner naming the file and the agent. A per-terminal counter
is exposed via <code>aiSecurity.sensitiveReads(terminalId)</code> so the
Security panel can show "3 sensitive reads this session" alongside the running
list.
</p>
<p>
<strong>What it cannot catch.</strong>
The bytes have already been transmitted by the time the watcher runs — the
transcript JSONL is downstream of the agent's tool runtime. Files exfiltrated
via subprocesses the agent invokes through arbitrary code (e.g.
<code>python -c 'open(".env").read()'</code>, network sockets opened by
langchain wrappers, MCP servers run by the agent itself) are only caught if the
wrapping <code>Bash</code> command parses cleanly to one of the known reader
commands. The watcher is intentionally conservative on the false-positive side —
flagging an irrelevant file once is cheap; missing a leak is expensive.
</p>
<h3 id="security-codechunk">Code-chunk + env-dump heuristics (v1.11.52)</h3>
<p>
Outbound prompts larger than 2 KB are inspected for code-shaped structure
(indentation density, braces/punctuation density, common keywords like
<code>function</code>/<code>class</code>/<code>import</code>/<code>def</code>,
and module declarations such as <code>import …</code> or <code>#include</code>).
When two or more of those signals fire, the prompt is flagged via a
<code>terminal:code-chunk-detected</code> event and an audit entry tagged
<code>code-chunk:<signals></code>. A separate detector counts
<code>UPPER_SNAKE=value</code> lines (with an optional <code>export</code>
prefix) — five or more triggers an <code>env-dump</code> flag and audit entry.
Both detectors are <em>heuristic</em>: the prompt is not blocked. They exist so
that a casual paste of an entire source file or <code>.env</code> does not slip
past unnoticed. False negatives are possible on minified or unusual code shapes.
</p>
<h3 id="security-egress">Per-agent egress audit (v1.11.52)</h3>
<p>
When an AI agent is launched, Termpolis starts a 60-second poller that asks
the OS what TCP connections the agent's PID has open
(<code>netstat -ano</code> on Windows, <code>ss -tnp</code> on Linux,
<code>lsof -nP -iTCP -p <pid></code> on macOS) and records each unique
remote <code>host:port</code>. The Security panel can read this back per
terminal so you can answer "did Claude talk to anything other than
<code>api.anthropic.com</code> today?". This is polling, not packet capture —
sub-minute bursts can be missed, and we do not reverse-DNS or inspect the
payload. If the platform tool is missing or the user has insufficient
permissions, the poller silently returns nothing and the rest of the app
continues to function.
</p>
<h3 id="security-tos-drift">Weekly ToS drift watcher (v1.11.52)</h3>
<p>
A scheduled GitHub Action
(<a href="https://github.com/codedev-david/termpolis/blob/main/.github/workflows/tos-drift.yml" target="_blank" rel="noreferrer"><code>.github/workflows/tos-drift.yml</code></a>)
runs every Monday at 13:00 UTC. It fetches the four provider pages this app
cites, normalises the HTML aggressively (strips
<code><script></code>/<code><style></code>/<code><svg></code>/<code><head></code>
and HTML comments, decodes entities, collapses whitespace), hashes the result,
and compares it to a snapshot committed under
<code>docs/security-snapshots/</code>. When a hash differs the action opens a
tracking issue tagged <code>security,tos-drift</code> so a human reviewer can
decide whether the legal language has materially changed and Termpolis needs
an update. The watcher detects rendered-text changes — it cannot infer legal
intent.
</p>
<h3 id="security-disclaimer">Legal disclaimer</h3>
<p>
The AI Security Center is <strong>best-effort, not regulatory-grade</strong>. The
project is licensed Apache 2.0 "AS IS". The full disclaimer ships in
<a href="https://github.com/codedev-david/termpolis/blob/main/TERMS.md" target="_blank" rel="noreferrer"><code>TERMS.md §5a</code></a>
and inside the app at Settings → Security. Provider terms can change without notice;
you must verify provider terms before transmitting confidential data. To the maximum
extent permitted by law, the authors and contributors of Termpolis disclaim all
liability for any data leak, breach, regulatory violation, contractual breach, or
business loss arising from your use of any AI agent launched through this application.
</p>
</section>
<!-- COPY FOR SLACK / TEAMS / PRs -->
<section id="copy-share" class="docs-section">
<h2>Copy for Slack / Teams / PRs</h2>
<p>
AI workflows generate share-worthy output constantly: a stack trace to dump into a
channel, a clean test run for a PR, a fenced code block for the engineering wiki.
Termpolis ships a four-way Copy submenu on every terminal context menu, plus the
keybinding <kbd>Ctrl+Shift+M</kbd> (rebindable) for the common case.
</p>
<h3>Copy as Code Block</h3>
<p>
Wraps the current selection — or the entire visible terminal buffer if nothing is
selected — in triple-backtick fences and copies it to the clipboard. Drop the result
into Slack, Teams, GitHub, GitLab, or any wiki that respects fenced code and the
monospaced layout survives.
</p>
<h3>Copy as Plain Text</h3>
<p>
Strips ANSI color escapes and copies the result as raw text. Use this for emails,
Jira tickets, Notion docs, or any surface where backticks would be noise.
</p>
<h3>Copy with Command</h3>
<p>
Prepends the last shell command (taken from history) to the copied output before
fencing. Reproducer-ready snippets for bug reports — your reviewer sees both the
command and the output in a single paste, instead of the usual back-and-forth.
</p>
<h3>Copy as Image (PNG)</h3>
<p>
Renders the underlying xterm.js canvas to a PNG via <code>canvas.toBlob</code> and
writes it to the clipboard with <code>ClipboardItem</code>. Paste straight into
Slack, Teams, or a Loom / wiki post. Colors, glyphs, and layout survive intact, so
you don't end up with the typical "weird mojibake in the screenshot" awkwardness
when the receiver is on a different OS or terminal font.
</p>
<p>
All four actions live in the terminal right-click menu under <strong>Copy →</strong>.
<kbd>Ctrl+Shift+M</kbd> defaults to Copy as Code Block; rebind it under Settings →
Keybindings.
</p>
</section>
<!-- INSTALL -->
<section id="install" class="docs-section">
<h2>Installation</h2>
<p>
Download the latest build from <a href="index.html#downloads">the downloads page</a> or
<a href="https://github.com/codedev-david/termpolis/releases/latest" target="_blank" rel="noreferrer">GitHub Releases</a>.
</p>
<div class="docs-table-wrap">
<table class="docs-table">
<thead>
<tr><th>Platform</th><th>File</th><th>Signed</th></tr>
</thead>
<tbody>
<tr><td>Windows</td><td><code>termpolis-setup-<ver>.exe</code></td><td>Code-signed</td></tr>
<tr><td>macOS (Apple Silicon)</td><td><code>termpolis-<ver>-arm64.dmg</code></td><td>Notarized</td></tr>
<tr><td>macOS (Intel)</td><td><code>termpolis-<ver>.dmg</code></td><td>Notarized</td></tr>
<tr><td>Linux (Debian / Ubuntu)</td><td><code>termpolis_<ver>_amd64.deb</code></td><td>—</td></tr>
<tr><td>Linux (other distros)</td><td><code>termpolis-<ver>.AppImage</code></td><td>—</td></tr>
</tbody>
</table>
</div>
<h3>Installing the .deb on Debian / Ubuntu</h3>
<p>
Use <code>dpkg</code>, <strong>not</strong> <code>sudo apt install ./termpolis*.deb</code>.
On Ubuntu 22.04+ apt drops to a sandboxed <code>_apt</code> user that can’t read
files in your home directory, which fails with
<em>“Permission denied / pkgAcquireRun: 13”</em>. <code>dpkg</code> doesn’t
drop privileges, so it works regardless of where the .deb is saved:
</p>
<pre><code>sudo dpkg -i ./termpolis_*.deb</code></pre>
<p>
The package’s postinst (v1.11.30+) takes care of the rest automatically:
it runs <code>apt-get install -f -y</code> to pull any missing transitive
dependencies (libgtk, libnss3, …), refreshes the desktop and hicolor
icon caches so the launcher icon shows up immediately, and ships the .desktop
entry with <code>--no-sandbox --disable-gpu</code> baked into the
<code>Exec=</code> line so the dock icon launches a working window on
NVIDIA / Wayland setups without any manual flags.
</p>
<h3 id="install-windows-defender">If Windows Defender quarantines Termpolis after install or auto-update</h3>
<p>
Termpolis is code-signed with an SSL.com OV certificate. Microsoft Defender’s
cloud ML classifier occasionally false-positives newly-released Electron apps
that haven’t yet accumulated SmartScreen reputation, typically flagging
<code>Termpolis.exe</code> as <em>Trojan:Win32/Cinjo.O!cl</em> or a similar
<code>!cl</code> (cloud) heuristic. Symptoms: the app refuses to launch, its
taskbar / Start Menu / Desktop shortcuts disappear, and the installed
<code>Termpolis.exe</code> shows blank version metadata.
</p>
<p>
To recover, open <strong>PowerShell as Administrator</strong> and run:
</p>
<pre><code>Add-MpPreference -ExclusionPath "$env:LOCALAPPDATA\Programs\Termpolis"
Add-MpPreference -ExclusionPath "$env:APPDATA\termpolis"
Add-MpPreference -ExclusionPath "$env:LOCALAPPDATA\termpolis-updater"
Add-MpPreference -ExclusionProcess "Termpolis.exe"
& "$env:ProgramFiles\Windows Defender\MpCmdRun.exe" -Restore -Name "Trojan:Win32/Cinjo.O!cl" -All
Start-Process "$env:LOCALAPPDATA\termpolis-updater\pending\Termpolis.Setup.*.exe"</code></pre>
<p>
The first four lines tell Defender to stop scanning Termpolis (preventing the
same FP on future auto-updates). The <code>-Restore</code> line pulls any
already-quarantined Termpolis files back out. The final line re-runs the most
recent pending installer to repair anything that went missing.
</p>
<p>
If you prefer the GUI: <em>Windows Security → Virus & threat protection
→ Protection history</em>, click the Termpolis detection, choose
<strong>Actions → Allow on device</strong>, then reinstall from the
<a href="index.html#downloads">downloads page</a>. Either way, please also
<a href="https://www.microsoft.com/en-us/wdsi/filesubmission" target="_blank" rel="noreferrer">submit the binary as a false positive to Microsoft</a>
— that’s what builds reputation and stops it happening to other users.
</p>
<h4>If your machine is corporate-managed (Intune / Tamper Protection locked)</h4>
<p>
On Azure AD-joined or Intune-managed devices, the steps above may silently
fail — including <strong>Allow on device</strong> in Protection History.
You can confirm this by running in PowerShell:
</p>
<pre><code>(Get-MpComputerStatus).TamperProtectionSource</code></pre>
<p>
If that returns <code>Intune</code> (or <code>EnterpriseClient</code>),
your IT department’s policy outranks local admin for any Defender
modification. Open a ticket with your IT/security team and ask them to add
one of:
</p>
<ul class="docs-list">
<li>A <strong>per-machine folder exclusion</strong> for <code>%LOCALAPPDATA%\Programs\Termpolis</code>, <code>%LOCALAPPDATA%\termpolis-updater</code>, and <code>%APPDATA%\termpolis</code>.</li>
<li>A <strong>process exclusion</strong> for <code>Termpolis.exe</code>.</li>
<li>(Most durable) A <strong>publisher exclusion</strong> for code signed by <code>CN=David Engelhart, O=David Engelhart, L=Savannah, S=Georgia, C=US</code> — covers every future Termpolis release without per-version updates.</li>
</ul>
<p>
Until IT processes the exclusion, the working stop-gap is to install an older
release that hasn’t been classified by Defender’s cloud model:
browse <a href="https://github.com/codedev-david/termpolis/releases" target="_blank" rel="noreferrer">GitHub Releases</a>,
pick the version right before the one that got flagged, and disable
auto-update in Termpolis Settings so it doesn’t re-pull the flagged
build.
</p>
<h3>Requirements</h3>
<ul class="docs-list">
<li>Windows 10 or 11 (x64)</li>
<li>macOS 10.15 (Catalina) or later, Apple Silicon and Intel builds ship separately</li>
<li>Linux: .deb for Debian/Ubuntu, AppImage for any other modern glibc distro</li>
<li>~200 MB disk; 512 MB RAM minimum, 2 GB recommended when running multiple agents</li>
</ul>
<h3>Data directory</h3>
<div class="docs-table-wrap">
<table class="docs-table">
<thead><tr><th>Platform</th><th>Path</th></tr></thead>
<tbody>
<tr><td>Windows</td><td><code>%APPDATA%\termpolis\</code></td></tr>
<tr><td>macOS</td><td><code>~/Library/Application Support/termpolis/</code></td></tr>
<tr><td>Linux</td><td><code>~/.config/termpolis/</code></td></tr>
</tbody>
</table>
</div>
</section>
<!-- API KEYS / BEFORE YOU BEGIN -->
<section id="api-keys" class="docs-section">
<h2>Before you begin · API keys</h2>
<p>
Termpolis is a terminal — it doesn't talk to AI providers itself. Each AI agent
(Claude Code, Codex, Gemini CLI, Qwen Code) is a separate CLI tool you launch
<em>inside</em> a Termpolis terminal, and that tool needs its own credentials.
Termpolis never asks you for an API key, never sees one, and never stores one.
</p>
<div class="docs-callout">
<p>
<strong>The minimum to be productive: pick one provider, install its CLI, set
its API key once.</strong> You do not need all four. A single agent is enough
to use every Termpolis feature except the multi-agent swarm.
</p>
</div>
<h3>Pick the agent that matches the account you already have</h3>
<div class="docs-table-wrap">
<table class="docs-table">
<thead>
<tr><th>If you have…</th><th>Use this agent</th><th>Install</th></tr>
</thead>
<tbody>
<tr>
<td>Anthropic / Claude.ai paid plan</td>
<td>Claude Code</td>
<td><code>npm install -g @anthropic-ai/claude-code</code></td>
</tr>
<tr>
<td>OpenAI / ChatGPT paid plan</td>
<td>Codex</td>
<td><code>npm install -g @openai/codex</code></td>
</tr>
<tr>
<td>Google AI Studio key, Vertex AI, or Code Assist (Workspace)</td>
<td>Gemini CLI</td>
<td><code>npm install -g @google/gemini-cli</code></td>
</tr>
<tr>
<td>Alibaba DashScope key (or want to run Qwen locally with Ollama)</td>
<td>Qwen Code</td>
<td><code>npm install -g @qwen-code/qwen-code</code></td>
</tr>
</tbody>
</table>
</div>
<h3>Setting the key (one-time, per provider)</h3>
<p>
Each CLI reads its key from an environment variable. Set it once in your shell's
startup file (<code>~/.bashrc</code>, <code>~/.zshrc</code>, or your PowerShell
profile) and Termpolis terminals will pick it up automatically. The exact variable
name per provider:
</p>
<div class="docs-table-wrap">
<table class="docs-table">
<thead>
<tr><th>Provider</th><th>Variable</th><th>Where to get the key</th></tr>
</thead>
<tbody>
<tr>
<td>Anthropic (Claude Code)</td>
<td><code>ANTHROPIC_API_KEY</code></td>
<td><a href="https://console.anthropic.com/settings/keys" target="_blank" rel="noreferrer">console.anthropic.com</a></td>
</tr>
<tr>
<td>OpenAI (Codex)</td>
<td><code>OPENAI_API_KEY</code></td>
<td><a href="https://platform.openai.com/api-keys" target="_blank" rel="noreferrer">platform.openai.com</a></td>
</tr>
<tr>
<td>Google AI Studio (Gemini)</td>
<td><code>GEMINI_API_KEY</code></td>
<td><a href="https://aistudio.google.com/apikey" target="_blank" rel="noreferrer">aistudio.google.com</a></td>
</tr>
<tr>
<td>Alibaba DashScope (Qwen)</td>
<td><code>DASHSCOPE_API_KEY</code></td>
<td><a href="https://dashscope.console.aliyun.com/apiKey" target="_blank" rel="noreferrer">dashscope.console.aliyun.com</a></td>
</tr>
</tbody>
</table>
</div>
<p>
Example, bash/zsh:
</p>
<pre class="docs-code"><code>echo 'export ANTHROPIC_API_KEY="sk-ant-..."' >> ~/.zshrc
source ~/.zshrc</code></pre>
<p>
Example, PowerShell:
</p>
<pre class="docs-code"><code>[Environment]::SetEnvironmentVariable('ANTHROPIC_API_KEY', 'sk-ant-...', 'User')</code></pre>
<p>
<strong>Heads-up about Gemini.</strong> The <code>gemini</code> CLI defaults to a
free OAuth tier when no env var is set, and Google may use that traffic to
improve products. Termpolis flags this in <strong>Settings → Security</strong>
and offers a <a href="#security-gemini">Strict Mode</a> that blocks the launch
until you set <code>GEMINI_API_KEY</code> (or another paid-tier signal).
</p>
<h3>Verifying it worked</h3>
<p>
Open a Termpolis terminal (<kbd>Ctrl</kbd> + <kbd>T</kbd>) and type:
</p>
<pre class="docs-code"><code>echo $ANTHROPIC_API_KEY # bash / zsh
$env:ANTHROPIC_API_KEY # PowerShell</code></pre>
<p>
If the value prints, you're done. If it's empty, restart Termpolis after editing
your shell's startup file so the new environment is inherited.
</p>
</section>
<!-- FIRST LAUNCH -->
<section id="first-launch" class="docs-section">
<h2>First launch (5 steps)</h2>
<p>
The first time you start Termpolis you'll see a four-step onboarding tour:
<em>What Termpolis is</em> → <em>Set an API key</em> → <em>Launch your first agent
(or swarm)</em> → <em>Security & crash reports</em> (opt-in checkbox). The
tour is one-time; you can revisit it any time from <strong>Help / Support →
Show tour again</strong>. After dismissing it you land on the welcome view. From
there:
</p>
<ol class="docs-list docs-list-ordered">
<li>
<strong>Pick a shell.</strong> Click any of the quick-launch buttons in the
center of the welcome view — bash, zsh, PowerShell, cmd, or whichever shells
Termpolis detected on your machine. A terminal pane opens.
</li>
<li>
<strong>(Optional) Open the AI Agents row.</strong> The sidebar has an
<strong>AI Agents</strong> section with one-click launchers for Claude Code,
Codex, Gemini CLI, and Qwen Code. A green check means the CLI is installed; a
red X means it isn't (click for install instructions). Skip this on the first
run if you just want to use Termpolis as a terminal.
</li>
<li>
<strong>Open Settings.</strong> Click the gear in the top-left of the sidebar
(or press <kbd>Ctrl</kbd> + <kbd>,</kbd>). Pick a theme, set your default shell,
and look at the Security tab if you launch any AI agent. Changes save instantly.
</li>
<li>
<strong>Save your first workspace.</strong> When you've got terminals you'd
want to come back to, click <strong>+ Save Workspace</strong> in the sidebar.
Termpolis snapshots the names, shells, themes, and working directories so they
restore the next time you open the app.
</li>
<li>
<strong>Press <kbd>Ctrl</kbd> + <kbd>/</kbd> any time</strong> to open the
in-app Help drawer — it covers every feature, every panel, and every keyboard
shortcut. You can also click <strong>Help / Support</strong> in the bottom
status bar.
</li>
</ol>
<figure class="docs-shot">
<img src="docs/screenshots/02-sidebar-default.png" alt="Termpolis sidebar in default state.">
<figcaption>The sidebar as it appears immediately after first launch.</figcaption>
</figure>
</section>
<!-- LAUNCH FIRST AI AGENT -->
<section id="first-agent" class="docs-section">
<h2>Launch your first AI agent</h2>
<p>
The fastest way to do something useful with Termpolis is to drive a single agent.
No swarm config, no MCP setup, no JSON. Once your <a href="#api-keys">API key</a>
is in place:
</p>
<ol class="docs-list docs-list-ordered">
<li>
<strong>Open the AI Agents section</strong> in the sidebar (it's the row above
Workspaces, with the robot icon).
</li>
<li>
<strong>Click the agent you want to run</strong> — Claude Code, Codex, Gemini
CLI, or Qwen Code. Termpolis opens a fresh terminal, sets the right working
directory, runs the agent's interactive command, and color-codes the tab so
you can see at a glance which agent is in which pane.
</li>
<li>
<strong>Type your task in plain English.</strong> Examples:
<ul class="docs-list">
<li><em>"Add a dark-mode toggle to the header component."</em></li>
<li><em>"Refactor <code>userService.ts</code> to use async/await throughout and add tests."</em></li>
<li><em>"Find every TODO in <code>src/</code> and tell me which ones look stale."</em></li>
</ul>
</li>
<li>
<strong>Watch the status bar.</strong> A colored badge appears next to the
agent name with running token cost. The
<a href="#observability-docs">Observability panels</a> light up the moment the
agent makes a tool call.
</li>
<li>
<strong>If the agent runs out of context</strong>, an amber banner offers a
<a href="#context-handoff">cross-AI handoff</a> — one click to continue the
same conversation in a different model with task, branch, and recent diff
already in scope.
</li>
</ol>
<p>
You don't need to configure MCP, edit any JSON, or set up tooling — Termpolis
auto-registers itself with each agent the first time you launch it. See
<a href="#mcp">MCP server</a> for what that actually unlocks.
</p>
<p>
Want to scale beyond one agent? Read <a href="#swarm-vs-single">Swarm vs. single
agent</a> next to decide whether your task is worth orchestrating.
</p>
</section>
<!-- SWARM VS SINGLE AGENT -->
<section id="swarm-vs-single" class="docs-section">
<h2>Swarm vs. single agent</h2>
<p>
Termpolis ships two ways to put AI to work. Pick the one that matches the shape
of your task — they're not interchangeable.
</p>
<h3>Quick decision tree</h3>
<ul class="docs-list">
<li>
<strong>Is the task one tight loop of "try → see → fix"?</strong>
→ <strong>Single agent.</strong> You're the conductor. Open Claude Code (or
whichever agent you trust most for this domain) and iterate.
</li>
<li>
<strong>Does the task split into independent chunks that can run in parallel?</strong>
(e.g. "build the API + write the migration + add tests + write docs", or
"rewrite three unrelated modules in the same style.")
→ <strong>Swarm.</strong> The conductor decomposes the task, hands subtasks to
the agents best-rated for each, and merges results.
</li>
<li>
<strong>Is the task a long spec rather than a single ask?</strong>
→ <strong>Swarm.</strong> Drop the spec into the Start Swarm wizard and let
the conductor plan.
</li>
<li>
<strong>Are you exploring or debugging interactively?</strong>
→ <strong>Single agent.</strong> Swarms are autonomous; an interactive back-and-forth
is the wrong shape for them.
</li>
<li>
<strong>Do you need different agents because they're individually best at
different sub-skills</strong> (e.g. Codex for tests, Gemini for docs)?
→ <strong>Swarm.</strong> The capability ratings drive routing for you.
</li>
</ul>
<h3>What you get with each</h3>
<div class="docs-table-wrap">
<table class="docs-table">
<thead>
<tr><th> </th><th>Single agent</th><th>Swarm</th></tr>
</thead>
<tbody>
<tr>
<td><strong>Setup</strong></td>
<td>Click an agent in the sidebar.</td>
<td><kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>S</kbd> → fill the Start Swarm wizard.</td>
</tr>
<tr>
<td><strong>Best for</strong></td>
<td>Iteration, exploration, debugging, learning.</td>
<td>Parallelizable specs, multi-skill tasks, autonomous runs.</td>
</tr>
<tr>
<td><strong>Cost</strong></td>
<td>Just the agent you're using.</td>
<td>Conductor + each agent it picks. Set a budget cap in the wizard.</td>
</tr>
<tr>
<td><strong>Visibility</strong></td>
<td>One terminal pane.</td>
<td>Swarm Dashboard (Tasks · Messages · Trace tabs). Agent terminals are hidden by default — the conductor drives them.</td>
</tr>
<tr>
<td><strong>You drive</strong></td>
<td>Every prompt.</td>
<td>The first prompt; the conductor takes it from there.</td>
</tr>
</tbody>
</table>
</div>
<p>
See <a href="#conductor">AI conductor</a> for the full swarm walkthrough or
<a href="#agents">AI agent profiles</a> for single-agent details.
</p>
</section>
<!-- SIDEBAR -->
<section id="sidebar" class="docs-section">
<h2>Sidebar</h2>
<p>The sidebar is the navigation spine of the app. From top to bottom:</p>
<ol class="docs-list docs-list-ordered">
<li>Termpolis logo: click to return to the welcome view.</li>
<li>Workspaces, one row per open workspace. See the <a href="#workspaces">Workspaces</a> section below for how they work.</li>
<li>Tool buttons, Settings, Git Panel, Workflows, Activity, Swarm, each toggleable.</li>
<li>Collapse/expand chevron, hides labels to save space.</li>
</ol>
</section>
<!-- WORKSPACES -->
<section id="workspaces" class="docs-section">
<h2>Workspaces</h2>
<p>
Workspaces are the <strong>project-level container</strong> in Termpolis. Think of
them as the tabs in a browser, except each one holds a full set of terminals, a
split/grid layout, an active agent, a scrollback history, per-workspace settings,
and any panels you've left pinned. You can run many workspaces side-by-side and
switch between them without losing state.
</p>
<h3>What a workspace owns</h3>
<ul class="docs-list">
<li><strong>Terminals</strong>, every open pty in that workspace, with its shell, working directory, label, color, and scrollback buffer.</li>
<li><strong>Layout</strong>, tab view, split view (the full pane tree), or grid view. Restored exactly on relaunch.</li>
<li><strong>Focus</strong>, which terminal was active, cursor position, selection.</li>
<li><strong>Agent sessions</strong>, any Claude Code, Codex, Gemini CLI, or Qwen Code runs tied to terminals in the workspace.</li>
<li><strong>Panel state</strong>, which side panels are open and their size.</li>
<li><strong>Per-workspace overrides</strong>, any setting scoped specifically to this workspace (shell default, font size, etc.).</li>
</ul>
<h3>How workspaces persist</h3>
<p>
Everything above is written to <code>session.json</code> in the Termpolis data
directory (see <a href="#install">Installation</a> for the per-platform path) as
soon as it changes, so an unclean shutdown still leaves you with last-known-good
state. Re-opening the app restores the workspaces in the same order with the same
terminals, split layouts, and focus.
</p>
<h3>Creating a workspace</h3>
<p>
Use the <strong>+ Workspace</strong> button at the top of the sidebar or the
<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>N</kbd> shortcut. Each new workspace
starts empty; pick a shell to open the first terminal, or apply a
<a href="#workflows">workflow template</a> to stamp a whole pre-built layout into it.
</p>
<h3>Managing workspaces</h3>
<p>Right-click any workspace row in the sidebar for:</p>
<ul class="docs-list">
<li><strong>Rename</strong>, changes the label in the sidebar and the window title when the workspace is active.</li>
<li><strong>Duplicate</strong>, creates a new workspace with the same terminal configuration (shell, cwd, label) but fresh, empty pty sessions. Useful when mirroring a setup for a second feature branch.</li>
<li><strong>Close</strong>, removes the workspace. If any terminals have live child processes, a confirmation dialog lists what's still running.</li>
<li><strong>Show in file explorer</strong>, opens the workspace's working directory in Finder / Explorer / your Linux file manager.</li>
</ul>
<h3>Switching between workspaces</h3>
<p>
Click a workspace row to activate it. Keyboard users can cycle with
<kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>[</kbd> / <kbd>]</kbd>. Unsaved terminal
output in background workspaces keeps streaming, nothing is paused just because
it's not visible.
</p>
<h3>Workspace root directory</h3>
<p>
Each workspace has a default working directory that new terminals start in. Set it
when you create the workspace, or change it later from Settings → Workspace.
Terminals started with the agent launcher or a workflow template inherit this unless
they override it per-terminal.
</p>
<h3>Workspaces vs. workflows</h3>
<p>
Workspaces are <em>long-lived containers</em> that own state across restarts;
<a href="#workflows">workflows</a> are <em>one-shot recipes</em> that populate the
current workspace with a pre-configured set of terminals, commands, and a split
layout. Think of a workspace as the room you're working in, and a workflow as the
"set the room up like this" macro. Launching a workflow inside a workspace closes
the existing terminals and replaces them with the workflow's terminals, the
workspace stays, the contents get reset.
</p>
</section>
<!-- TERMINALS -->
<section id="terminals" class="docs-section">
<h2>Terminals</h2>
<figure class="docs-shot">
<img src="docs/screenshots/03-new-terminal-modal.png" alt="New terminal modal with shell + agent options.">
<figcaption>The new-terminal modal with shell, cwd, and agent profile options.</figcaption>
</figure>
<p>
Every pane is a full pty-backed terminal powered by <code>node-pty</code>, real TTY
semantics, xterm escapes, signal forwarding. Not a shim.
</p>
<p>Create one with <kbd>Ctrl</kbd> + <kbd>T</kbd>. Pick a shell, a working directory, optionally an agent profile, plus a label and color.</p>
<figure class="docs-shot">
<img src="docs/screenshots/04-terminal-running.png" alt="A running PowerShell terminal in Termpolis.">
<figcaption>A running terminal, copy on selection, 256-color palette, mouse scroll.</figcaption>
</figure>
<p>
Closing a terminal with an active process prompts for confirmation, this protects