newt-tui 0.8.0

Newt-Agent TUI surfaces (ratatui): code mode + pilot mode
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
//! Command help content and its plain/Markdown presentation.
//! Command recognition and dispatch remain with the session.

use newt_core::agentic::newt_line;
use newt_core::role_profile::Cognition;

/// Map a typed command (incl. aliases) to its help topic. Several commands
/// share one page (the editor modes; the conversation-end trio).
pub(super) fn canonical_help_topic(cmd: &str) -> &str {
    match cmd {
        "quit" => "exit",
        "end" | "restart" | "clear" => "new",
        "allow" => "permissions",
        "plan" => "roadmap",
        "compact" => "compress",
        "vi" | "vim" | "emacs" | "nano" | "edit-mode" => "editor",
        "tool-rounds" | "max-rounds" => "rounds",
        _ => cmd,
    }
}

/// The `/cognition` page, with its level list and wire mapping derived from
/// [`Cognition::all`] so a renamed or added level cannot leave it stale.
static COGNITION_PAGE: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| {
    let all = Cognition::all();
    let levels: Vec<&str> = all.into_iter().map(Cognition::label).collect();
    let (light, deep) = (all[0], all[all.len() - 1]);
    format!(
        "\
/cognition — folded into /psyche (#1665)

  /psyche                open the dial panel (TTY); ←/→ dials cognition
  /psyche cognition <level>  set {levels}
  /psyche cognition off      send no reasoning controls (override any persona)
  /psyche cognition auto     follow the active persona's cognition (default)
  /psyche cognition list     list every level, light → deep

Responses maps the level to OpenAI reasoning.effort ({light}={} …
{deep}={}). Chat Completions maps it to local generation controls only
when the endpoint explicitly advertises that capability; unknown endpoints are
unchanged. The session override beats the active persona's cognition; a
persona sets its own default via `cognition:`.",
        light.reasoning_effort(),
        deep.reasoning_effort(),
        levels = levels.join(" | "),
    )
});

static TENACITY_PAGE: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| {
    let levels: Vec<&str> = newt_core::Tenacity::all()
        .into_iter()
        .map(newt_core::Tenacity::label)
        .collect();
    format!(
        "\
/tenacity — folded into /psyche (#1665)

  /psyche                open the dial panel (TTY); ←/→ dials tenacity
  /psyche tenacity <level>   set {levels}
  /psyche tenacity auto      clear the override (back to normal)
  /psyche tenacity list      list every level

Tenacity is how long the agent pursues the task. `relentless` lifts the
initial tool-round allowance; an explicit `/rounds` overrides that initial value.
Fresh progress can renew either allowance; `workflow_grace_rounds = 0` makes
it a hard cap. Tenacity is set only explicitly (flag, /psyche, a conversation's pin, obsessive), never by a
persona or config. How soon the agent acts is initiative: /help initiative.",
        levels = levels.join(" | "),
    )
});

static INITIATIVE_PAGE: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| {
    let levels: Vec<&str> = newt_core::Initiative::all()
        .into_iter()
        .map(newt_core::Initiative::label)
        .collect();
    format!(
        "\
/psyche initiative — how much the agent looks before acting

  /psyche                open the dial panel (TTY); ←/→ dials initiative
  /psyche initiative <level>   set {levels}
  /psyche initiative auto      clear the override; inherit persona / config / family
  /psyche initiative list      list every level with its round count

Higher initiative nudges the model to edit after fewer read-only rounds, and
decisive / eager make exit_plan_mode require a concrete edit. The session
override wins over the persona's `initiative` and the [initiative] config;
`auto` (aliases `inherit` / `reset`) releases it. The model family supplies
the default ([initiative.families]); the rounds per level are
[initiative.rounds].",
        levels = levels.join(" | "),
    )
});

/// A single-page `--help` for one command — usage, what it does, and a couple of
/// examples. `None` for an unknown topic. Kept terse on purpose: newt's help is
/// a one-screen reference (the man-page-style browser is gilamonster's job).
pub(super) fn command_help_page(cmd: &str) -> Option<&'static str> {
    let page = match canonical_help_topic(cmd) {
        "settings" => {
            "\
/settings [field value] — the main entry point for session controls

On a rich terminal, /settings opens an index:
  Session      model, editor, reasoning, effort dials, prompt, and rounds
  Permissions  permission posture and prompted-decision audit
  Workspaces   saved directories and access for the next process launch
  Audit        settings receipts and verification
  Backends     choose, edit, add, or remove a backend
  Themes       presets, per-role colors and attributes, live preview, and save

Use arrows then Enter, or a section's letter (t for Themes); / filters the
index. Esc clears the filter, then leaves the index for chat.
In Themes, Enter accepts a typed color; Enter again applies and persists the
draft. Applying or cancelling with Esc returns to Settings. Ctrl-S saves a
named copy; Enter applies it. Backends opens its
separate chooser, which returns to chat when closed.

The text form works everywhere; bare /settings uses it outside a rich terminal:
  /settings thinking fold
  /settings rounds 40
  /settings workspaces       interactive operator editor for next-launch access

/model, /backends, /permissions, and /workspace remain direct shortcuts."
        }
        "models" => {
            "\
/models · /models capabilities — inspect the active endpoint's models

  /models                arrow-key model picker on a rich terminal; text list otherwise
  /models capabilities   the matrix: Tool Use, Think (reasoning), Ctx Win,
                         Safe Ctx, tuning Conf, and tested date

Untested rows show '—'; classify one with /probe <model>. Per-model overrides
live in [model_tuning] (see /config)."
        }
        "model" => {
            "\
/model [name] — choose or switch the model on the active backend

Changes the model newt talks to. The choice sticks across runs (saved to
~/.newt/settings.toml) but does not edit config; switching backends clears it.
On a rich terminal, /model opens the live model list: arrows move, Enter
selects, Esc cancels. /models opens the same picker. Resident models show a
[loaded] badge after the name; the active model and badge use theme colors.
On a llama.cpp router: l loads the highlighted model, u unloads it, x unloads
other resident models then loads the highlighted one. Unloading requires
confirmation. These controls change memory residency, not files; Enter picks
the model for chat. r refreshes server state.
In a lean or piped session, /models prints the list and /model <name> switches.
  /model qwen3:30b"
        }
        "backend" => {
            "\
/backend — an alias of /backends (#2048)

They were never two commands the operator should have had to tell apart, and
the slash registry always described them as one. See /help backends."
        }
        "backends" => {
            "\
/backends [name] — the backend panel, the text list, or a switch by name

Bare /backends on a rich interactive terminal opens the panel: ←/→ spins
through the configured backends, ◀ marks the active one; Enter applies the
pick; Esc leaves silently. `e` edits the selected entry, `a` adds one (name,
kind, url, model, api-key env/file — written crash-safe to
~/.newt/backends/<name>.toml), and `d` removes one after confirming, naming
what is lost and where from.

The text forms work everywhere (piped, lean build, headless):
  /backends            list every configured backend, ◀ the active one
  /backends dgx1       repoint this session at the 'dgx1' backend

A backend's WIRE KIND (openai / ollama) is a field on the backend itself,
edited with `e` in the panel. `/backend <kind>` used to set it globally,
detached from the endpoint it applied to — which is how a session ends up
pointed at an OpenAI-wire URL in Ollama mode. Pick a named backend that
already has the kind you want instead.

Your choice sticks across runs (~/.newt/settings.toml); an explicit
NEWT_PROVIDER or a --loadout still overrides it."
        }
        "crew" => {
            "\
/crew edit [name] — edit a crew's settings interactively

Prompts field-by-field (planner/navigator/triage loadouts, control loop, test
command, and budgets), previews the result, then writes it as a bare-Crew TOML
to ~/.newt/crews/<name>.toml. Enter keeps the [current] value; '-' clears an
optional field. Same form as `newt crew --edit`.
  /crew edit            edit the sole crew (or be prompted for a name)
  /crew edit home       edit (or create) the 'home' crew"
        }
        "thinking" => {
            "\
/thinking — folded into /settings (#2044)

  /settings                    open the form; the reasoning row is in it
  /settings thinking fold      (default) the first `/spill N` rows of
                               reasoning, then one line saying how long it
                               thought and what is behind the fold, reopenable
                               with the `/spill open <id>` it names
  /settings thinking stream    every line, unbounded — the historical trickle
  /settings thinking off       just the answer

`on` is an alias for `fold`. Reasoning is dimmed and sits above the answer
either way; TTY only. Persist with [tui] thinking in config."
        }
        "tenacity" => TENACITY_PAGE.as_str(),
        "initiative" => INITIATIVE_PAGE.as_str(),
        "cognition" => COGNITION_PAGE.as_str(),
        "psyche" => {
            "\
/psyche — the agent's effort posture: cognition, tenacity, initiative, crew

  /psyche                open the dial panel (TTY): ↑↓ select, ←→ dial,
                         Enter apply, Esc leave (nothing changed → just exits)
                         rows: persona · model (spins the backend's served
                         models, applied via the /model path) · cognition ·
                         tenacity · initiative
  /psyche status         the read-only text view (also what piped/lean gets)
  /psyche cognition <level|off|auto|list>   text setter for the cognition dial
  /psyche tenacity <level|auto|list>        text setter for the tenacity dial
  /psyche initiative <level|auto|list>      text setter for the initiative dial
  /psyche obsessive      engage the max-effort posture's live dials

The orthogonal psyche dials:
  cognition   backend-specific reasoning depth per call
  tenacity    how long it pursues the task (relentless lifts the round limit)
  initiative  how much it looks before acting (the read → act nudge)
  crew        how many minds work the task    (NEWT_TEAM / newt crew)

obsessive = cognition meticulous + tenacity relentless + crew on — newt's
'ultra'. Initiative is left alone: the deepest thinking and acting after one
round pull against each other. In-session /psyche obsessive sets cognition +
tenacity live; crew is a launch gate, so start with `newt --obsessive` to
include the crew this session."
        }
        "probe" => {
            "\
/probe [model|all] · /probe window <model> · /probe reset

Classify models empirically; results feed /models capabilities.
  /probe <model>        warm up, then test: tool conformance, context window,
                        thinking quirk, token calibration
  /probe                probe the active model
  /probe all            RE-probe every model on the endpoint (a long sweep —
                        press Esc to cancel; finishes the current model first)
  /probe window <model> empirical input-boundary search (max input at High conf)
  /probe reset          wipe all learned values (conformance, windows,
                        calibration) so the next /probe re-learns from scratch"
        }
        "memory" => {
            "\
/memory — show context-window and notes usage

Read-only: how full the context window is, persistent NOTES usage, and the
session compression counters. Add facts with /remember; compact with /compress."
        }
        "compress" => {
            "\
/compress [focus] — compress the conversation context now

Summarize-and-prune the in-flight context to reclaim window, optionally biased
toward a topic. Runs automatically when the window fills; this forces it early.
  /compress
  /compress the auth refactor"
        }
        "summarizer" => {
            "\
/summarizer [subcommand] — inspect or manage the mid-loop summarizer

  /summarizer                  show the effective backend + knobs
  /summarizer setup [alias]    provision the default/named embedded mini-model
  /summarizer embedded [alias] pin an explicit embedded summarizer override
  /summarizer fallback <m>     set fallback_model (use 'none' to clear)
  /summarizer timeout <secs>   set timeout_secs
  /summarizer retries <n>      set retries
  /summarizer keep-alive <v>   set keep_alive (use 'none' to clear)
  /summarizer clear            remove summarizer.toml, return to built-in default

This is the interactive wrapper around `newt summarizer ...`."
        }
        "rounds" => {
            "\
/rounds [show|<n>|double|reset|config|unlimited] — initial tool-call round allowance

Human-only override for the initial allowance in each turn. Fresh evidence,
workspace changes, and new verification can renew it automatically without
operator nudges. Set `workflow_grace_rounds = 0` for a hard round cap.
Explicit inference budgets, cancellation, and the no-progress brake still apply.
This command does not edit config and lasts only for this session.
  /rounds             show the initial allowance
  /rounds 50          start with 50 tool-call rounds per turn
  /rounds double      double the current initial allowance
  /rounds reset       clear the override; derive from tenacity + config/model
                      (`default` and `auto` are aliases)
  /rounds config      use config/model tuning even under relentless tenacity
  /rounds unlimited   raise to at least 10000 rounds (effectively run-until-finished)

Aliases: /tool-rounds, /max-rounds."
        }
        "remember" => {
            "\
/remember <fact> — add a fact to persistent NOTES.md

Writes a durable note the agent carries across turns and sessions (workspace
NOTES). Survives /new. View usage with /memory.
  /remember the staging DB is read-only"
        }
        "new" => {
            "\
/new · /end · /restart · /start — begin a new conversation

/new, /end, and /restart FINALIZE the current conversation (its summary is
extracted to memory) and start a fresh one, staying in the session. /start
switches to a fresh one too but leaves the previous conversation OPEN so you can
/resume it. /start <title> and /rename <title> name a conversation so it is easy
to find in /resume. Nothing auto-resumes on next launch (#1030) — use /resume to
reopen a past conversation. /exit · /quit · vi :wq leave the session."
        }
        "conversation" => {
            "\
/conversation <sub> — manage saved conversations

  /conversation list              list saved conversations
  /conversation show <id>         print one
  /conversation restore <id>      switch the session to it
  /conversation rename <id> <t>   retitle it
  /conversation delete <id>       delete it (alias: rm)

ids accept a unique prefix. Search bodies with /recall."
        }
        "recall" => {
            "\
/recall [query] — browse or search past conversations

  /recall            recent conversations in this workspace
  /recall <query>    full-text search across this workspace's turns

Read-only and workspace-fenced. Bring one back with /conversation restore <id>
or /resume."
        }
        "resume" => {
            "\
/resume [query|n|id] — find and REOPEN a past conversation (#1030)

  /resume            list recent conversations, annotated by liveness
  /resume <query>    full-text search this workspace's turns
  /resume <n>        reopen the n-th row from the last listing
  /resume <id>       reopen by id or unique prefix

Markers: ▶ current · ● open in another newt · ○ resumable. Reopening a
conversation another live newt holds is refused (it would mix turns) —
this is how #1030 keeps multiple newts from colliding."
        }
        "transcript" => {
            "\
/transcript — review the WHOLE current conversation (#1670)

On the RICH surface: a full-screen pager where the conversation spine —
your › prompts and the model's ▸ replies — is the structure. Scroll
freely; the grey per-turn tool blocks are folded behind ⚙ headers.

  q / Esc          leave the pager (the screen is restored)
  ↑↓ / j k         scroll by line        PgUp/PgDn      page
  Ctrl-U / Ctrl-D  half page             g / G          top / bottom
  n / p            next / previous message (jump the spine)
  Enter/Space/Tab  fold or unfold the current turn's tool block

On the LEAN surface the same command PRINTS the spine into scrollback —
the plain scroller has no scroll regions, by charter. Tool detail shown
is the stored summary (name · ok · duration); raw tool output is never
persisted."
        }
        "roadmap" => {
            "\
/roadmap [sub] — manage the per-session planning roadmap

  /roadmap list             list open roadmaps
  /roadmap show             render the active roadmap tree
  /roadmap new              create a new roadmap
  /roadmap use <n>          bind a roadmap by number
  /roadmap add <title>      add a roadmap item
  /roadmap task <n>         show one task
  /tree                     render the active roadmap tree (alias of /roadmap show)

Alias: /plan"
        }
        "persona" => {
            "\
/persona <sub> — configured personas

  /persona list           list configured personas
  /persona show           show the active persona
  /persona <name>         start a fresh conversation with that persona
  /persona switch <name>  same as /persona <name> (an explicit verb)
  /persona clear          start fresh with no persona

Setting or clearing a persona starts a new conversation (the system prompt
changes). Define personas in config."
        }
        "dgx" => {
            "\
/dgx <sub> — NVIDIA DGX endpoint operations

  /dgx status       endpoint health + currently-loaded models
  /dgx models       models installed on the DGX
  /dgx ps           models currently loaded in VRAM
  /dgx warm [model] pre-load a model into VRAM (cuts first-token latency)
  /dgx pull <model> pull an Ollama or HuggingFace GGUF model onto the node
  /dgx rm <model>   delete a model from the DGX
  /dgx route <task> recommend a formation for a task
  /dgx doctor       probe every configured endpoint

  Note: flags like --dry-run/--force/--name are CLI-only; use
  `newt dgx pull ...` from a shell for the full pull workflow."
        }
        "permissions" => {
            "\
/permissions — review prompted permission decisions + the active posture

Read-only: what you've allowed/denied this session and the posture's optional
authority floor, when configured. This view does not change grants. Eligible
permission prompts can save approvals; /settings workspaces edits saved
directory profiles for the next process launch.

For full access inside one directory, start:
  newt --workspace-access code <directory>
Commands can create, change, rename, and delete inside that workspace; native
filesystem confinement still rejects outside targets, including symlink and
parent-directory escapes. Network access remains separately configured.
The default preset can also be set in trusted [tui.permissions] configuration.
This startup choice does not change a running session's authority.

For full access inside one directory, start:
  newt --workspace-access code <directory>
Commands can create, change, rename, and delete inside that workspace; native
filesystem confinement still rejects outside targets, including symlink and
parent-directory escapes. Network access remains separately configured.
The trusted-config equivalent is [tui.permissions] preset = \"workspace_full_access\".
This startup choice does not change a running session's authority.

Usage:
  /permissions                overview of this session's prompt flow
  /permissions audit [N]      newest N audit rows from the persisted permission log
  /allow                      alias for /permissions

Examples:
  /permissions                # show current session decisions
  /permissions audit 25       # show newest 25 rows from permission-log.jsonl
  /allow                      # alias for /permissions"
        }
        "status" => {
            "\
/status — show session status and environment summary

  workspace, backend, mode, posture, permissions state, and active identifiers.

Tip: use /info for a slightly richer version, and /permissions for full
prompted-decisions history."
        }
        "info" => {
            "\
/info — show machine-readable context for the current session

Shows the same status surface as /status, plus the version, active model
identity, and resolved backend details that drive this prompt.
        "
        }
        "byline" => {
            "\
/byline — show the Co-authored-by block the next commit would carry

  Read-only. Prints the exact trailer block, in commit order:

    every model that has contributed since the last commit (a /model,
    /backend, loadout, or crew switch ADDS one — it never replaces one),
    then the model driving this turn, then the human operator when a real
    email is known, then the Harness: provenance line.

  The email in a trailer identifies the HARNESS, not the model, so a
  harness signs its own address and never another's. Under newt's own
  address the account name is not repeated: the qualifier carries only
  what the address does not already say — `(v<version> <build>)`, or
  `(crew v<version> <build>)` for a crew leaf. A foreign harness keeps its
  full name, e.g. `(Claude Code v2.1.239)`.

  The operator by-line comes from your git identity (user.name +
  user.email). If no real email is known it is OMITTED, never invented —
  so a missing operator line means \"unknown\", not \"nobody\".

  This is rendered by the same finalizer the commit path runs, so it
  cannot show a shape a commit would not produce. Do not hand-write these
  trailers: the `git` tool stamps them itself."
        }
        "docs" => {
            "\
/docs — open the right docs quickly

  GitHub README: https://github.com/Gilamonster-Foundation/newt-agent
  issue tracker: https://github.com/Gilamonster-Foundation/newt-agent/issues
  architecture docs: https://github.com/Gilamonster-Foundation/newt-agent/tree/main/docs

Use /help for the in-session command list."
        }
        "mcp" => {
            "\
/mcp — manage MCP servers for this session

  /mcp                         server manager (text status without a rich TTY)
  /mcp off [name]              mute this session (tools leave the catalog now;
                               connection stays — /mcp on restores instantly)
  /mcp on [name]               unmute this session (bare = unmute all)
  /mcp disable <name>          durable: write enabled=false to config + drop now
  /mcp enable <name>           durable: write enabled=true; choose Reconnect in MCP
  /mcp auth <name>             how to (re)authenticate (`newt auth <name>`)

The same manager is under /settings → MCP. Enter opens server → tools → details;
Up/Down navigates, Esc returns one level. Login reconnects after successful
authentication; Reconnect refreshes the child/catalog; Test lists tools only.
Tool effect hints are metadata, never permission grants.

on/off is session-scoped (like /nudge) — use it while testing schema budget.
enable/disable rewrites ~/.newt/config.toml."
        }
        "mode" => {
            "\
/mode [name] — show or choose the session's operating mode

  /mode              show the active mode and describe every available mode
  /mode list         same as bare /mode
  /mode show         show only the active mode
  /mode <name>       select chat, dev, admin, plan, diagnose, auto, or full-auto
  /mode reset        return to chat (the default)

Modes guide working style. Plan may update Newt's plan ledger but cannot mutate
the workspace; diagnose is bounded read-only research. In Auto, the model may
select chat, dev, admin, plan, or diagnose for a later action-shaped turn;
protected intake still wins, and only the human can select full-auto. No mode
grants authority or bypasses the active permission posture."
        }
        "posture" => {
            "\
/posture [name] — show or choose a configured permission posture

  /posture              show the active posture and configured names
  /posture list         same as bare /posture
  /posture show         show only the active posture
  /posture status       same as /posture show
  /posture <name>       preload skill/framing and apply its optional preset floor
  /posture off          clear the active posture
  /posture clear

Configured postures continue to use [modes.<name>] entries for compatibility.
A configured preset can only NARROW authority, never widen it; a posture with
no preset leaves authority unchanged."
        }
        "loadout" => {
            "\
/loadout — show the active loadout

Prints the declared axes (backend, model, persona, mode, …) and what each
actually resolved to, so you can see why the session is configured as it is."
        }
        "workspace" => {
            "\
/workspace — operator editor for saved workspace access

  /settings workspaces      the same interactive editor
  /status workspace         read-only current workspace path

Choose a workspace, additional read/write directories, a confined command/write
preset, and a default working directory inside the workspace. Optionally select
a default workspace for future launches. Review the resolved paths and confirm;
Cancel is the default. Settings and keys must remain protected from model access.

Saved changes require a real Newt process restart; /restart only resets the
conversation. Current authority and jobs stay unchanged. Removing a profile or
directory does not remove separate approvals or access through a parent grant.
Network permissions and configured development-command extras remain separate.
The model and noninteractive surfaces cannot approve changes in this editor."
        }
        "spill" => {
            "\
/spill [status|N|reset|summary|excerpt|last|open ID] — tool-output controls

  /spill                 show the effective row count and live availability
  /spill <N>             set collapsed live and completed rows for later tools
  /spill reset           return to the configured [tui] spill_lines value
  /spill 0               disable live display; show completed output unbounded
  /spill summary         collapse spilled results to one line (rich default)
  /spill excerpt         restore the multi-row excerpt for spilled results
  /spill last            open the newest retained result (rich, this session)
  /spill open <ID>       open the retained result named by a collapse marker
  F4 (cockpit)           choose retained output without submitting a prompt
  F4 (decision prompt)   inspect the pending request; Esc returns without answering

While a tool is active, Up/Down scroll retained output. Space or Enter toggles
the boundary: ⧉ expands up to the terminal's safe capacity; ▣ collapses it.
Completed bodies are memory-only and bounded; older IDs can expire."
        }
        "config" => {
            "\
/config — dump the resolved configuration (secrets redacted)

Shows the effective config after merging /etc/newt, ~/.newt, and ./.newt — the
source of truth for backends, loadouts, model tuning, and [tui] settings.
api_key_file/env values are redacted."
        }
        "prompt" => {
            "\
/prompt · /prompt set \"<tmpl>\" · /prompt reset — customize the input prompt

  /prompt                  list tokens ($MODEL/$DATE/…, \\m/\\t/\\M/…) + current
  /prompt set \"<template>\"  set the prompt for this session
  /prompt reset            revert to [tui] prompt / the built-in default

Tokens: \\t time · \\m model · \\M edit mode · \\w workspace · \\u user · \\h host ·
\\v version. Persist by putting a template in [tui] prompt (prefer the $NAME
macros there to dodge TOML escaping)."
        }
        "editor" => {
            "\
/vi · /emacs · /nano — switch line-editor key bindings for this session

  /vi      modal vi keys (Esc=NORMAL; i/a/o insert; :w send, :wq send+end+quit)
  /emacs   emacs/readline keys (Enter sends; Ctrl-O newline; C-x C-c exit)
  /nano    nano-style (Enter sends; ^X exit; ^G help)

Persist with [tui] edit_mode. Press Ctrl-h/^G/:help in-editor for the cheatsheet."
        }
        "version" => {
            "\
/version — print the newt-agent version."
        }
        "exit" => {
            "\
/exit · /quit (or bare exit/quit, Ctrl-D) — leave the session

Ends the session. Conversations do NOT auto-resume on next launch (#1030): each
launch starts fresh — use /resume to reopen a past conversation. (Opt into
auto-resuming the folder's latest with [conversations] resume = true.)"
        }
        "help" => {
            "\
/help [command] — command help

  /help            list every command
  /help <command>  this page for one command (same as /<command> --help)

Add --help (or -h) to any command for its page."
        }
        _ => return None,
    };
    Some(page)
}

/// Render one command's `--help` page to a `String`; `bool` is `true` when a
/// page exists. Unknown topics render a one-line miss (so a typo doesn't fall
/// through to the wrong handler) and return `false`.
///
/// This is the single byte-source for a plain per-command page. The interactive
/// TUI derives its Markdown document from the same [`command_help_page`]
/// corpus, while the startup-free CLI routes through [`render_help`].
fn command_help_output(cmd: &str, color: bool, verbose: bool) -> (String, bool) {
    match command_help_page(cmd) {
        Some(page) => {
            let mut out = newt_line(
                &format!("/{} help", canonical_help_topic(cmd)),
                color,
                verbose,
            );
            out.push('\n');
            for line in page.lines() {
                out.push_str(line);
                out.push('\n');
            }
            (out, true)
        }
        None => {
            let mut out = newt_line(
                &format!("no help for '/{cmd}' — /help lists every command"),
                color,
                verbose,
            );
            out.push('\n');
            (out, false)
        }
    }
}

/// Render the bare-`/help` command list to a `String`.
///
/// The plain top-level list: the `Available commands:` narrator line followed
/// by every [`help_lines`] entry. The interactive TUI derives its Markdown
/// document from that same corpus; plain mode and the startup-free CLI
/// ([`render_help`]) route through this function.
fn help_list_output(color: bool, verbose: bool) -> String {
    let mut out = newt_line("Available commands:", color, verbose);
    out.push('\n');
    for line in help_lines() {
        out.push_str(line);
        out.push('\n');
    }
    out
}

/// Markdown source for RichTUI's bare command catalog. The long-standing
/// [`help_lines`] corpus remains the single source of truth; this only gives
/// each row Markdown structure so the renderer preserves command boundaries
/// instead of folding their soft line breaks into one paragraph.
fn help_list_markdown() -> String {
    let mut out = String::from("## Available commands\n\n");
    for line in help_lines() {
        let line = line.trim();
        if line.is_empty() {
            out.push('\n');
        } else if let Some((usage, description)) = line.split_once(" - ") {
            out.push_str(&format!("- `{usage}` — {description}\n"));
        } else {
            out.push_str(line);
            out.push('\n');
        }
    }
    out
}

/// Markdown source for one command's detail page.
fn command_help_markdown(cmd: &str) -> Option<String> {
    let page = command_help_page(cmd)?;
    let mut out = format!("## /{} help\n\n", canonical_help_topic(cmd));
    for line in page.lines() {
        if line.starts_with("  ") {
            out.push_str("- ");
            out.push_str(line.trim());
        } else {
            out.push_str(line);
        }
        out.push('\n');
    }
    Some(out)
}

/// Render help for the interactive TUI. Markdown mode is deliberately a
/// presentation layer over the existing corpus: disabling it returns the
/// byte-identical plain/startup-free output from [`render_help`].
pub(super) fn render_help_for_tui(
    topic: Option<&str>,
    color: bool,
    verbose: bool,
    markdown: bool,
    cols: usize,
) -> String {
    if !markdown {
        return render_help(topic, color, verbose);
    }
    let source = match topic {
        None => help_list_markdown(),
        Some(cmd) => match command_help_markdown(cmd) {
            Some(source) => source,
            None => return render_help(topic, color, verbose),
        },
    };
    let rendered = newt_core::agentic::render_markdown(
        &source,
        newt_core::agentic::RenderOpts { color, cols },
    );
    format!("{}{rendered}\n", newt_line("", color, verbose))
}

/// Print one command's `--help` page; `true` when a page exists.
pub(super) fn print_command_help(cmd: &str, color: bool, verbose: bool, markdown: bool) -> bool {
    let found = command_help_page(cmd).is_some();
    print!(
        "{}",
        render_help_for_tui(
            Some(cmd),
            color,
            verbose,
            markdown,
            newt_core::tty::term_cols(),
        )
    );
    found
}

/// Render newt's command help WITHOUT starting a session or connecting to a
/// backend. `topic == None` is the bare-`/help` command list; `Some(cmd)` is
/// that command's detail page (an unknown topic renders the one-line miss).
///
/// This is the startup-free entry point behind `newt help [command]` and the
/// interactive TUI's plain-render fallback. [`help_lines`] and
/// [`command_help_page`] remain the single source of truth for WHAT help says
/// (issue #548 measures that content); RichTUI only adds a Markdown
/// presentation over those corpora.
pub fn render_help(topic: Option<&str>, color: bool, verbose: bool) -> String {
    match topic {
        None => help_list_output(color, verbose),
        Some(cmd) => command_help_output(cmd, color, verbose).0,
    }
}

pub(crate) fn help_lines() -> &'static [&'static str] {
    &[
        "  /settings [field value]  - main settings index: Session · Permissions · Audit · Backends · Themes; text setters also work",
        "  /models                  - list the models the active backend serves, marking the active one",
        "  /models capabilities     - the same list as a matrix: tool use, thinking, context window, tuning",
        "  /model [name]            - pick a model, or switch by name (sticks across runs)",
        "  /backends [name]         - backend panel on a rich TTY (choose · edit · add · remove); text: list, or switch by name",
        "  /backend                 - alias of /backends",
        "  /probe [model|all]       - classify tool use, context window, thinking, calibration (all = re-probe every model; Esc cancels)",
        "  /probe window [model]    - empirical input-boundary search (records max input at High confidence)",
        "  /probe reset             - wipe all learned probe values (conformance, windows, calibration)",
        "  /compress [focus]        - compress context now, optionally focused on a topic (alias: /compact)",
        "  /summarizer              - show or change the summarizer backend and knobs",
        "  /rounds [n|double|reset|config|unlimited] - set this session's initial tool-call round allowance",
        "  /context                 - show the active context manager + features",
        "  /context manager [preset] - show or set the strategy preset (standard; progressive/distributed pending #546)",
        "  /context feature <name> [on|off] - toggle a composable context feature (all pending #582-#586)",
        "  /context compaction [headroom_aware|message_count|reset] - set this session's automatic-compaction trigger policy",
        "  /context stats           - experimentation dashboard: budget, compression, feature states",
        "  /search <query>          - semantic code search cockpit (#1387): preview · model · rejects · pin · exclude · status",
        "  /remember <fact>         - add a fact to persistent NOTES.md",
        "  /discuss [text]          - talk through a pending clarification batch instead of answering it (alias: /chat); \
         says so if nothing is pending",
        "  /new                     - finalize this conversation and start a fresh one (stays in the session; alias: /clear)",
        "  /end                     - the same, recorded as ended by /end rather than /new (it no longer exits — use /exit)",
        "  /restart                 - the same, recorded as a restart",
        "  /start [title]           - begin a new conversation, leaving the current one open to /resume",
        "  /resume [name|search|n|id] - find & reopen a past conversation: bare lists recent, then match by name/title, id, or full-text search",
        "  /resume find [query]     - search conversations WITHOUT reopening one (bare: browse)",
        "  /resume list             - list saved conversations",
        "  /resume show <id>        - show a saved conversation",
        "  /resume restore <id>     - restore a saved conversation",
        "  /resume rename <id> <title> - rename a saved conversation",
        "  /resume delete <id>      - delete a saved conversation (asks first; alias: rm)",
        "  /name <title>            - retitle the current conversation so it is easy to find in /resume (alias: /rename)",
        "  /transcript              - review this conversation: full-screen pager (rich) / printed spine (lean)",
        "  /roadmap [sub]           - #1030 plan tree: new·list·show·use·add · next·bind·done·eval·drive · task <n> commit [sha] · issue <n> <#> · export·import [path]",
        "  /roadmap tree            - render the active roadmap tree (▶ marks the next-ready node / DFS cursor)",
        "  /persona list            - list configured personas",
        "  /persona show            - show the active persona",
        "  /persona <name>          - start fresh with a persona",
        "  /persona switch <name>   - same as /persona <name> (an explicit verb)",
        "  /persona clear           - start fresh with no persona",
        "  /crew edit [name]        - edit a crew's settings (roles, control loop, test, budgets)",
        "  /setup [host]            - configure an inference backend (wizard, or probe a host); \
         pasted keys are stored encrypted",
        "  /dgx status              - DGX endpoint health + running models",
        "  /dgx models              - list models installed on the DGX",
        "  /dgx ps                  - models currently loaded in VRAM",
        "  /dgx warm [model]        - pre-load a model into VRAM",
        "  /dgx pull <model>        - pull an Ollama/HuggingFace GGUF model onto the node",
        "  /dgx rm <model>          - delete a model from the DGX",
        "  /dgx route <task>        - recommend a formation for a task",
        "  /dgx doctor              - probe every configured endpoint",
        "  /mode [name]             - show/set operating style: chat, dev, admin, plan, diagnose, auto, full-auto",
        "  /posture [name]          - show/set configured posture; permission floor is optional",
        "  /permissions             - prompted decisions + active permission posture",
        "  /ocap propose            - show this session's grant candidates from its flight-recorder capture",
        "  /ocap propose save       - also write them, unsigned, to approve.toml (existing entries kept)",
        "  /workspace               - review and save workspace access for the next process launch",
        "  /settings workspaces     - open the same operator workspace editor",
        "  /status                  - session and environment summary (the default view)",
        "  /status <topic>          - config · version · workspace · loadout · byline · memory · models · info",
        "  /dock [status|disable|enable] - remote-HTMX docking kill-switch (req 7): disable forcibly undocks THIS box from every hub; status lists approved peers",
        "  /allow                   - alias for /permissions",
        "  /nudge <on|off|status>   - action-pressure nudges (narration rescue etc.); off = answer-in-peace mode",
        "  /psyche                  - effort dial panel: cognition, tenacity, initiative, persona (Esc exits; /psyche obsessive = max)",
        "  /mcp [on|off|enable|disable|auth] [name] - MCP manager; session mute (on/off) or durable config (enable/disable)",
        "  /spill [status|N|reset|summary|excerpt|last|open ID] - tool output",
        "  /prompt                  - list prompt tokens ($MODEL, $DATE, …) + current prompt",
        "  /prompt set \"<template>\"  - set the prompt for this session; /prompt reset to revert",
        "  /vi  /emacs  /nano       - switch line-editor key bindings for this session",
        "  ! <command>              - run a host command interactively (e.g. ! pa login) — you, not the agent",
        "  /cd [dir]                - change the session working dir (shown in prompt), confined below the start dir; bare /cd returns to the root — use ! for pwd/ls/rm/…",
        "  Esc                      - while the agent is working: interrupt the turn, back to your prompt",
        "  Up/Down                  - while a tool is active: scroll its retained output",
        "  Space/Enter              - while a tool is active: toggle ⧉ expand / ▣ collapse",
        "  /search [query|preview|model|rejects|pin|exclude|status|clear] - #1387 semantic search cockpit",
        "  /nav                     - the code navigator; bare lists its verbs",
        "  /nav def <symbol>        - goto definition ([SYMBOL])",
        "  /nav text <regex>        - lexical search ([LEXICAL])",
        "  /nav uses <symbol>       - find references (usage index)",
        "  /nav tests <symbol>      - related tests (heuristic)",
        "  /nav map [unit]          - project map; optional expand unit",
        "  /nav callers <symbol>    - inbound edges (GRAPH regex-floor)",
        "  /nav callees <symbol>    - outbound edges (GRAPH regex-floor)",
        "  /nav implementations <symbol> - implementors (GRAPH regex-floor)",
        "  /nav hierarchy <symbol>  - type hierarchy (GRAPH regex-floor)",
        "  /nav type <symbol>       - inspect_type (not typechecker-proved)",
        "  /nav impact <unit>       - outbound/reverse deps (+ optional lcov)",
        "  /nav retrieval [turn N] [human|model|diff] - retrieval ledger",
        "  /nav compare <what>      - compare retrieval: semantic lexical · turn A B · index",
        "  /nav export <json|markdown> - export retrieval ledger",
        "  /help [command]          - this command list, or one command's detail page",
        "  /exit  /quit  exit  quit - leave the session",
        "",
        "  Add --help (or -h) to any command — or /help <command> — for its detail page.",
    ]
}