Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
2e2b5ed
manual: space space no longer opens home, esc does
ZeroPoint95 Sep 21, 2026
d862337
chat: home has a hint row, and the tip table grows to thirty on two b…
ZeroPoint95 Sep 22, 2026
95b69bb
home: the tip sits right over the rule with a bulb and a cross, and t…
ZeroPoint95 Sep 22, 2026
9948337
chat: @ works on home, /attach takes any path and opens the browser b…
ZeroPoint95 Sep 22, 2026
daa9308
chat: one tip list on both boxes, the conversation's tip row after a …
ZeroPoint95 Sep 22, 2026
ced0ee3
chat: /manual puts the question to the model as a turn, ctrl+b freeze…
ZeroPoint95 Sep 22, 2026
85d452b
chat: a showing is a tip that stood twenty seconds, the ledger forgiv…
ZeroPoint95 Sep 22, 2026
b91a391
chat: copy mode is gone — ctrl+b and /copy do nothing, the mouse copies
ZeroPoint95 Sep 22, 2026
25dd945
chat: the tip cross moves the row on, /project takes /folder's home half
ZeroPoint95 Sep 22, 2026
38c6c08
chat: the cross holds the row blank until the row leaves the frame
ZeroPoint95 Sep 22, 2026
559fcf2
chat: the owner's read of the tip list — twenty-six rows, five respelled
ZeroPoint95 Sep 22, 2026
2331389
chat: the /attach browser tip reads "lets you browse"
ZeroPoint95 Sep 22, 2026
6cb8a02
Restore double-space Home navigation and ask-here choices
ZeroPoint95 Sep 23, 2026
f3071a5
Format restored rewind state fields
ZeroPoint95 Sep 23, 2026
28bbee1
Align restored Home instructions with current panels and controls
ZeroPoint95 Sep 23, 2026
2407055
Cover restored Home controls in real terminals and align remaining hi…
ZeroPoint95 Sep 23, 2026
d24b68c
Exercise both Home submission routes and stopping through the built t…
ZeroPoint95 Sep 23, 2026
5561960
Document restored Home controls for #1388
ZeroPoint95 Sep 23, 2026
89addc5
Validate restored Home with live models and await terminal cleanup
ZeroPoint95 Sep 23, 2026
b41b8c6
Check that populated Home sessions omit their empty hint
ZeroPoint95 Sep 23, 2026
de0d935
chat: twenty-three tips — /ask, /folder and the second /attach row co…
ZeroPoint95 Sep 23, 2026
8be1fc0
chat: a conversation's tip goes back to the keys row, on its old mech…
ZeroPoint95 Sep 23, 2026
50c134a
chat: the /manual tip stops at "about codeaf"
ZeroPoint95 Sep 23, 2026
83a824f
chat: the @ tip says what the list is for — finding paths
ZeroPoint95 Sep 23, 2026
f64fe03
chat: /remember and /standing stop saying the same word
ZeroPoint95 Sep 23, 2026
ba5c0bf
chat: twenty-two tips — ctrl+. comes off the table
ZeroPoint95 Sep 23, 2026
9532714
docs: the change entry for the tip wave
ZeroPoint95 Sep 23, 2026
d2bdfdd
chat: the ctrl+enter tip says a rule, the way /standing's row does
ZeroPoint95 Sep 23, 2026
1fae72c
Rename the Home scheduled heading to standing
ZeroPoint95 Sep 23, 2026
35e4211
Merge dev — the working logo meets a branch with no copy mode
ZeroPoint95 Sep 23, 2026
b84f0a1
Merge #1388 — two spaces go home again, and esc goes back to its old …
ZeroPoint95 Sep 23, 2026
8a33f03
Revert "chat: copy mode is gone" — the feature stays, only its tip goes
ZeroPoint95 Sep 23, 2026
ae67d1f
chat: the rewind tip names both doors, the chord and the command
ZeroPoint95 Sep 23, 2026
95ed821
chat: seven tips in the owner's words
ZeroPoint95 Sep 23, 2026
79fc218
chat: a taken /project says nothing, and home's keys row stays up
ZeroPoint95 Sep 23, 2026
c82c867
chat: the search place refuses again when memory is off
ZeroPoint95 Sep 23, 2026
9ed1ec0
Merge dev into restore-home-shortcuts — #1415, #1424 and #1425 meet t…
AbirAbbas Sep 24, 2026
df0889e
docs: the Home heading rename is #1415's entry, not this one's
AbirAbbas Sep 24, 2026
80b7a5c
tests: the tmux rig sees the setup form at forty-four columns
AbirAbbas Sep 24, 2026
ae442b8
chat: home's folder sheet stays about the next conversation when the …
AbirAbbas Sep 24, 2026
034f316
manual: two spaces open home again, and the pinned project is on the …
AbirAbbas Sep 24, 2026
02ef0dd
Merge #1388's head — dev through #1425 and the narrow-setup rig fix
AbirAbbas Sep 24, 2026
ffa9471
Merge dev into restore-home-shortcuts — #1422's project click meets a…
AbirAbbas Sep 24, 2026
e9b1903
Merge #1388's head again — #1422's project click on home
AbirAbbas Sep 24, 2026
17809f7
manual: a pasted folder's leftover text goes to the project on the ke…
AbirAbbas Sep 24, 2026
7c4e161
Merge dev — #1388 landed as 9ad949ae3, whose tree is the #1388 head a…
AbirAbbas Sep 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions docs/GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ keeps the last ten cleared drafts; `enter` restores one and `d` lets one go.
| `/budget` | `what codeaf may spend · every limit on one tab` |
| `/compact` | `summarize the conversation now` |
| `/rewind` | `go back to an earlier point · esc esc takes back the last` |
| `/manual` | `codeaf's own manual · every page, one per line` |
| `/manual` | `asks the model what codeaf can do, from its own manual` |
| `/help` | `this list` |
| `/quit` | `close this conversation` |
| `/drafts` | `cleared-but-kept drafts · enter restores one, d lets one go` |
Expand Down Expand Up @@ -330,7 +330,8 @@ in `config.json`, memory in `graph.db`, and project sessions under `v3/projects/
The Markdown under `internal/manual/chat/` is compiled into codeaf, and the conversation
reads it with the `manual` tool to answer questions about its own behaviour. From a
terminal `codeaf manual` lists every page and `codeaf manual "<question>"` returns the
sections that answer it; inside the chat it is `/manual`. Build gates require every
sections that answer it; inside the chat `/manual` puts the question to the model with
the manual open, and the answer arrives as a turn. Build gates require every
slash command and alias, every tool name, and more than a hundred questions in ordinary
language to reach an answering page.

Expand Down
37 changes: 37 additions & 0 deletions docs/changes/unreleased/1389-one-tip-list-two-boxes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
kind: changed
title: one list of twenty-two tips, said two ways — home rotates them, a conversation ranks them
pr: 1389
surface: [chat, docs]
invalidates:
- "Home never drew an earned tip: the picker refused the page outright. Home now has a tip row directly above the rule over its box, right-aligned, led by a bulb and closed by a cross a pointer can press."
- "A hint row named which box it could draw beside, and the conversation's foot ranked its rows by a per-row `priority` number. There is ONE table now and no priority column: the table's own order is the ranking, every row draws on both boxes, and a row filed under home's slot fails the build."
- "Copy mode had a tip on the list, `ctrl+b freezes the screen so you can read and copy from it`. It has none. THE FEATURE IS UNTOUCHED — ctrl+b freezes the viewport, v/a/y work in it, /copy opens it, and the mouse copies alongside it through OSC 52 — and only the row teaching it came off. This branch deleted copy mode for one day on 2026-09-22 and put it back on 2026-09-23 at the owner's word, so a memory of it being gone is a memory of that day."
- "/image was a command that attached a picture. It is gone from the table, the dispatch, home's gate and the path completion; /attach already told a picture from a file by its name, and typing /image is answered as any unknown word is."
- "/folder did two different things depending on the screen it was typed on — gave a conversation a folder, or pinned the folder the next conversation opens in. The pin is /project now, which is home's alone: `/project <path>` takes the path and opens nothing, a bare /project opens the browser, and in a conversation it says which screen it lives on. /folder means one thing everywhere, and never moves the directory codeaf is standing in."
- "/attach took a file. It takes a file or a folder — a folder goes through the same seam /folder uses — and a bare /attach on home opens the browser aimed at the next conversation's folder."
- "Home's box had no @ completion, and the project sat on home's rule. The @ list works on home now (files and folders, never tasks), and the project moved to the right end of the keys row under the box, in a conversation as well as on home."
- "/manual printed the manual's pages as written with no model call. It is a turn now: the question goes to the model, told to answer from the manual tool and name the page. The as-written reading is still `codeaf manual` at the terminal."
- "The Workspace tab's row was `ui.hints` meaning shown. The row reads `disable hints`, off by default; the persisted key keeps its bytes and internal/config inverts once on the way in and out."
- "A showing was every visible change of hands of a tip row. On home a showing is now a tip that stood twenty seconds where it could be seen; in a conversation it is one session, counted when the slot takes the tip. A ledger written under the old rule is read once with the rows that rule spent forgiven, and the tips a gesture retired stay retired."
- "The rewind tip read `/rewind takes back an earlier message`, and for one day `esc esc takes back the last message`. It names both doors — `esc esc or /rewind takes back an earlier message` — because #1388 gave the chord back and a row teaching only the chord leaves nobody a word to type into `/` or ask the manual about. Either door retires it."
- "For one day this branch taught esc as the door home, after the surface stopped treating two spaces that way on 2026-09-17. #1388 restored the gesture, so TWO SPACES IN AN EMPTY BOX open home and esc is the interrupt, the layer peel and the arming half of rewind. Every manual passage and every test here says so."
---
There is one table of tips and there are two boxes, and the wave ends with the
two boxes saying them by rules of their own, because a conversation is a screen
you sit in and home is a screen you pass through.

A CONVERSATION RANKS. The tip is the lowest rung of the keys row at the foot,
taken from the rest state and outranked by every state with keys of its own.
The first eligible row in the table's order wins, so a tip that has just become
true is said at once, and a gap of two turns keeps a busy first session from
reading as a slideshow. No clock, no cross.

HOME ROTATES. The tip is the row over the rule, and every tip that is true gets
its turn — moving on with every visit and every two minutes at rest. The cross
means enough of these for now: the row goes blank and nothing takes its place
until home itself leaves the frame, and the tip put away is charged nothing.

The list is twenty-two rows, from a survey of forty-eight lines worth saying
and three reads of the whole thing by the owner. Using a gesture on either box
retires its tip on both.
24 changes: 18 additions & 6 deletions internal/config/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -2679,14 +2679,26 @@ func (s *Settings) build() []Setting {
read: func() string { return formatBool(DraftPersistAt(dir)) },
write: func(raw string) error { return writeBool(dir, KeyDraftPersist, raw) },
},
// THE ROW READS THE OTHER WAY UP FROM ITS KEY. `ui.hints` persists
// whether tips are SHOWN, and keeps doing so — a persisted identifier keeps
// its bytes — while the row a person reads is `disable hints`, off by
// default (the owner's word for it, 2026-09-22). The inversion lives here,
// once, so the chat's settings panel and `codeaf config` cannot disagree.
Setting{
Key: KeyHints, Category: CategoryInterface, Kind: SettingBool,
Label: "hints",
Hint: "one-line tips above the message box, each shown until the key or command " +
"it names has been used once. Off silences them, and the what's-new line a " +
"new build may say with them. A change lands at the end of the next turn.",
read: func() string { return formatBool(HintsAt(dir)) },
write: func(raw string) error { return writeBool(dir, KeyHints, raw) },
Label: "disable hints",
Hint: "on silences the one-line tips — the keys row's in a conversation and the " +
"row above the rule on home — and the what's-new line a new build may say " +
"with them. Off, the default, shows each tip until the key or command it " +
"names has been used once. A change lands at the end of the next turn.",
read: func() string { return formatBool(!HintsAt(dir)) },
write: func(raw string) error {
disabled, err := parseBool(raw)
if err != nil {
return err
}
return writeProfileValue(dir, KeyHints, !disabled)
},
},
Setting{
Key: KeyAttribution, Category: CategoryInterface, Kind: SettingBool,
Expand Down
4 changes: 2 additions & 2 deletions internal/manual/chat/asking-from-home.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ Yes. Type it on the home screen, press `↑` once — which lands on the row spe
```
? ask here: "remind me at 6 to leave"
+ start a new conversation: "remind me at 6 to leave"
─ glm-5.3-flash:auto · ◇ asks ─── project: ~/codeaf
─ glm-5.3-flash:auto · ◇ asks ──────────────────────────────────────────────
› remind me at 6 to leave
enter starts a new conversation and sends this · ↑ ask here · ↑↑ pick a match · alt+p project · alt+e effort · alt+a approvals · esc clear
enter starts a new conversation and sends this · ↑ ask here · esc clear project: ~/codeaf
```

What you get is **a row in home's conversation list and a pane holding the exchange**. The row
Expand Down
64 changes: 30 additions & 34 deletions internal/manual/chat/attaching-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,11 @@ more than one — and `enter` does exactly what it says. Over `--host`, the shee
machine you are sitting at and selected files travel with the message. "Choosing a folder"
is the full account of that sheet, its keys and its preview.

Path rules are `/image`'s: `~` is your home directory, a bare name is under the directory
this conversation is about, and an absolute path is left alone. Tab completes the path as
you type it. Over `--host`, that completion walks the machine you are sitting at, because
Path rules: `~` is your home directory, a bare name is under the directory this
conversation is about, an absolute path is left alone, and a path wrapped in quotes or with
its spaces backslashed — `/attach '/Users/me/Screenshot 2026-09-18 at 1.35.20 PM.png'`, the
shape Finder and a terminal drop hand you — is read as the one path it is (until
2026-09-22 that was answered `no such file`). Tab completes the path as you type it. Over `--host`, that completion walks the machine you are sitting at, because
those are the bytes `/attach` is about to send.

The file lands on the tray as its own chip — `▤ server.log`, or `+ server.log` on a
Expand Down Expand Up @@ -253,7 +255,7 @@ local only when its distro is this WSL distro.

`/mnt` is WSL's default automount root. If `[automount] root` in `/etc/wsl.conf` names
another root, codeaf uses that instead: `root = /drives` makes `c:/Users/…` read from
`/drives/c/Users/…`. This applies to a drag, a pasted path, `/attach`, `/image`, `/export`,
`/drives/c/Users/…`. This applies to a drag, a pasted path, `/attach`, `/export`,
and a local copy destination chosen in `/files` because all use the same path reading.

## I copied a screenshot and pasted it — nothing happened
Expand All @@ -271,7 +273,7 @@ only in the clipboard, save it as a file first.

## A drop into a box that already holds a command

**It stays text, and that is on purpose.** Type `/attach ` or `/image ` first and then
**It stays text, and that is on purpose.** Type `/attach ` first and then
drop the file: the path is the command's argument, and turning it into `[image #1]` would
break the one line on this surface whose whole job is to take a path. `enter` then runs
the command and the file lands on the tray by that road instead.
Expand Down Expand Up @@ -337,7 +339,7 @@ swept away while the transcript still refers to it.
Yes — this is what `/attach` does over `--host`, and it is the point of it.

The path you type is anchored to **this** machine, the one you are sitting at, exactly the
way `/image` and the `@` completion are. You are naming a file on your own laptop. Its
way the `@` completion is. You are naming a file on your own laptop. Its
bytes travel with the message, and the far machine writes them down under that
conversation's `attachments/` folder before the turn opens.

Expand Down Expand Up @@ -395,8 +397,8 @@ The numbers come from the wire, not from taste: a whole message travels as one l
line may weigh 64MB, and bytes inside it cost a third more than the file does. 16MB per
file leaves room for two large ones, a screenshot and the sentence they came with.

Pictures are counted separately and have their own ceiling of **10MB each** — see the
`/image` refusals.
Pictures are counted separately and have their own ceiling of **10MB each** — see *What
codeaf says when a picture is refused* on the keys page.

## Every refusal /attach can give you

Expand Down Expand Up @@ -434,23 +436,26 @@ used to answer
`<name> is a folder · attach a file`; locally it now goes to the folder door and says
`folder · ~/code/thing`. Over `--host`, it registers nothing and says
`choosing a folder is not available over --host yet — the folders here are this machine's, not the ones the conversation is on.`
On home it pins the next conversation's folder instead and says
`next conversation opens in ~/code/thing`, because there is no conversation there to attach
one to. Dropping a folder on the window still refuses with the old
On home it pins the next conversation's folder instead, because there is no conversation
there to attach one to: it says nothing, and `project: ~/code/thing` at the right of the keys
row under the box shows the pin. Dropping a folder on the window still refuses with the old
`<name> is a folder · attach a file` sentence — see "Choosing a folder".

## Attaching a file from home — /attach on the home screen, before there is a conversation

**Home has a tray of its own and `/attach <path>` fills it.** No conversation is opened for
it: the chip appears above home's box, home says
`attached · server.log · rides with the next conversation`, and the file is attached to the
first message of whatever conversation you start next. `/image <path>` is the same for a
picture, and a drop or a paste onto home does it with no command at all.
first message of whatever conversation you start next. A picture goes the same way, and a
drop or a paste onto home does it with no command at all.

**A bare `/attach` there asks for the path** — `type the path after /attach · or drop the file
here` — rather than opening the browser. `/folder` is the browser on local home, and it is
aimed at which folder the next conversation opens in (see "Choosing a folder"). Over
`--host`, `/folder` says why this machine's folder cannot be that far conversation's folder.
**A bare `/attach` there opens the browser**, the same sheet a bare `/project` opens, aimed
at the folder the next conversation opens in; a file chosen on it lands on home's tray and a
folder chosen on it becomes that folder. (Until 2026-09-22 it answered `type the path after
/attach · or drop the file here` — rather than opening the browser.) `/project` is the
browser on local home, and it is aimed at which folder the next conversation opens in (see
"Choosing a folder"); `/folder` on home opens a conversation first and browses there. Over
`--host`, both say why this machine's folder cannot be that far conversation's folder.

**The tray survives the walk.** Attach a file on home, go into a conversation, come back: it
is still there. Home's tray row cannot be clicked; a chip comes off on a conversation's own
Expand All @@ -464,23 +469,14 @@ engine: an attached file arrived with no name
engine: "../../etc/passwd" is a path and not a name — an attachment names itself and the engine chooses where it goes
```

## Attaching a picture is a different thing
## Attaching a picture is a different thing — is there an /image command

`/image <path>` is the door for a picture, and a picture travels **as content** so it can
actually be looked at.

You do not have to remember which word is which. **A picture handed to `/attach` is still
treated as a picture** — it goes on the tray as `▣ #1 shot.png`, gets its `[image #1]`
token in your sentence, and is looked at rather than read. png, jpeg, webp and gif are the
five codeaf accepts.

The reverse is not true: `/image` refuses anything that is not one of those five, with

```
<name> is not a picture · png, jpeg, webp and gif are
```

so `/attach` is the general word and `/image` is the specific one.
There is one word, `/attach`, and it tells a picture from a file by the name: **a picture
handed to `/attach` is treated as a picture** — it goes on the tray as `▣ #1 shot.png`, gets
its `[image #1]` token in your sentence, and travels **as content** so it can actually be
looked at rather than read. png, jpeg, webp and gif are the five codeaf accepts; anything
else is a file. There is no `/image` command: until 2026-09-22 it was a second word that
took only pictures and refused the rest, and it is gone.

On the tray the two are told apart by their own glyph — `▣ #1 shot.png` for a picture,
`▤ server.log` for a file — and by the number, which only a picture carries. In the
Expand All @@ -499,7 +495,7 @@ left in the box as text; it is not any more, because over `--host` a path in a s
names a file the far machine has never seen, and a chip is what makes the bytes travel.

To keep a dropped path as *text* — to talk about a path rather than send the file — type
`/attach ` or `/image ` first and drop onto that line, or write the path yourself after
`/attach ` first and drop onto that line, or write the path yourself after
some words. A box that already begins with `/` keeps the path as the command's argument.

Over `--host` the difference matters more than it looks. A path left as plain text is a
Expand Down
Loading
Loading