Terminal sessions
A terminal session is an interactive shell that DataMind Oda opens for itself and keeps alive between steps, so multi-step work keeps its place: the working folder, exported variables, defined functions and programs left running all stay in the session. This page is the reference for how a session lives: how it starts, when Oda considers it ready, how sends settle, and how it ends.
The actions Oda takes in a session, with their parameters, results and markers, are on Terminal tools. For the in-app view of the same shells, see Terminal sessions.
What a session is
- An interactive shell, kept between steps. Oda opens it in the chat's workspace folder and reuses it across steps; one send finishing does not end the session.
- State stays in place. The working folder, exported variables, defined functions and any program the session left running persist from one send to the next.
- Its own prompt. A session shows the controlled prompt
oda> .
- Process-local. Sessions live inside the running app. They do not survive a restart of Oda, and nothing is restored afterwards.
- Nothing starts on its own. A session exists only after Oda opens it; no session starts at app start.
- Owned by one chat. A session belongs to the exact chat that opened it. Another chat, or a helper Oda runs for part of the task, is refused even when it knows the session's id.
- Not the side-panel terminal. The terminal in your side panel is yours; you open it and type in it. See The terminal.
- Not the command shells. The bash and PowerShell shells that run Oda's commands are a separate feature with their own rules. See Persistent shells.
The life of a session
- Open. Oda asks for a session, usually of the default shell type, and can give it a display name such as
main or gdb. A session exists only after the shell starts successfully; a failed start is reported and rolled back, never left half-created.
- Send. Oda writes input and waits for the session to settle. One send runs at a time per session; a second send is refused until the first settles.
- Read. Oda reads the output the session kept, in pages, continuing from where a previous read stopped.
- Stop. Stopping a send interrupts what is running with a real signal, delivered after the pending write settles; Oda never types a control character into the session. A cancelled send keeps its place until the pending write and the interrupt have both settled.
- Close. Closing stops the watching, ends the shell and its whole process tree, and settles any send that was still waiting. Closing is safe to repeat.
When Oda considers a session ready
Oda settles a send using three kinds of evidence, and the result says which one settled it:
- The prompt came back. Oda follows the shell's own prompt marker: when the verified prompt returns and the shell holds the foreground again, the session is ready for the next input.
- The input was read. After the first write, one exact reading can show that the session read its input.
- Quiet counts as idle. Once a prompt has been seen, three seconds of silence, plus a half-second grace, settle the wait as idle.
| Wait reason | What it means |
|---|
stdin_read | The session took the input and is waiting for more. |
inferred_idle | The session went quiet; this suggests the command finished, but it is not proof. |
timeout | The wait reached its limit before the session settled. |
session_exit | The shell itself ended, rather than a command finishing. |
An idle or timed-out wait never proves that the foreground command exited: the command can still be running when the wait ends.
Output and reads
- Output is kept as text lines: control sequences, colours and cursor movement are stripped, and line endings are normalised, because a session is made for commands that read and print text.
- The kept window holds the newest output, up to 10,000 lines or 4 MiB; beyond that, the oldest lines drop off first.
- A single read never returns more than 256 KiB of text; a cut lands on a character boundary and is marked
[output truncated].
- Reads page through what is kept, and a truncation sticks: once earlier output has been dropped, a read reports which lines of the kept window it returned and never presents a partial window as the whole output.
Sizes, timings and their checks
A session starts on these defaults:
| Setting | Default |
|---|
| Shell | bash by default; PowerShell can be selected instead |
| Screen | 40 rows by 160 columns |
| Kept output | 10,000 lines, up to 4 MiB |
| Largest single read | 256 KiB |
| Checks while settling | every 50 ms |
| Exact check after the first write | 150 ms |
| Silence counted as idle | 3 seconds, plus a 500 ms grace |
| Waiting for a send | 30 seconds |
| Close grace | 3 seconds |
- Oda starts the shell without your profiles or startup files: bash runs with
--noprofile --norc -i and PowerShell with -NoLogo -NoProfile; paging programs are switched off and colour is off, so output stays plain.
- An explicit shell command or argument set replaces the dialect defaults; an empty value falls back to them.
- Oda checks these values as the app starts: they must be positive numbers, the single-read cap cannot be larger than the kept-output cap, and the idle grace cannot be shorter than one settling check.
Confinement and secrets
A session runs inside the chat's access mode, the same way Oda's commands do; the modes are described on Command sandboxing and approvals.
- Full access starts the shell directly, with no limits applied.
- Read Only and Workspace Write start the shell confined. On a computer where the app cannot confine a shell, the session does not start: Oda reports that the mode cannot confine a shell here, and it never falls back to running the shell unconfined.
- A mode change is refused while a chat has sessions open or a session is still being created: close the open sessions and wait for any session still being created to settle, then change the mode.
- Oda removes its own ambient secrets from the environment before the shell starts, so they are not present inside a session.
Refusals and failures
Every refusal names the session, the name or the reason involved, so a case is easy to describe when you report it. In plain words:
- No shell for the type. A session type with no shell behind it is refused.
- Not yours to use. A session that belongs to another chat, an id nothing holds any more, a session that is already closing, and sessions that are shutting down with the app are refused, each naming what is wrong.
- Busy. A second send while one is active is refused until the first settles.
- A name is taken. Two sessions in one chat cannot share a display name; a name another session already uses, or one that is already being created, is refused.
- A start failed. If the shell ends while the session is starting, or misses its readiness deadline, no session opens; the message carries the exit code or the signal when one is known.
- A close failed. A close that cannot end the processes cleanly reports the failure instead of claiming success, and closing many sessions reports how many could not be closed.
Background sends
A send can run in the background, so Oda keeps working while the session runs the command:
- The send becomes a job that belongs to the chat. Oda reads its output with the job tools and stops it the same way, and a stopped background send reads as
killed. See Background runs and jobs.
- The job's reader keeps a byte cursor: each read continues from where the last one stopped, so output is not shown twice, and a read taken before the send starts comes back empty rather than failing.
Questions, answered
Why was an action on a session refused?
An action has to come from the exact chat that opened the session, and it has to name a session that still exists. Another chat's session, an id nothing holds any more, a session that is already closing, and sessions shutting down with the app are refused, each naming what is wrong. The chat that holds the session can still use it; for anything else, Oda opens a new session.
How does Oda know a session is ready for the next input?
Oda follows the shell's own prompt marker: when the verified prompt returns and the shell holds the foreground again, the session is ready. After the first write, one exact reading can show that the input was read. Once a prompt has been seen, three seconds of silence, plus a half-second grace, also settle the session as idle.
Why is a session still busy after I stopped a send?
Stopping a send does not free its place at once. The send keeps the session's single slot until the pending write and the interrupt have both settled, and the next send can start only after that.
What happens to a waiting send when the session closes?
Closing ends the wait: the send settles as a session exit, and the shell with everything running under it ends. The session then reads as closed.
Can I name a session, and why was a name refused?
Yes; a session can carry a display name such as main or gdb. Names are per chat: a name another session in the same chat already uses, or a name that is already being created, is refused. Leaving the name out is always fine.
How long does a terminal session live?
While the app runs and while the chat that opened it lives. A session is not shared with other chats and is not restored after a restart of Oda; when its chat is gone, the session is gone with it. Oda opens a fresh session when it next needs one.
What does it mean when closing a session reports a failure?
The close could not end the shell and its processes cleanly, so Oda reports the failure instead of claiming success; closing many sessions reports how many could not be closed. Ask Oda to close the session again, and keep the message, which names the reason.
Why does session output arrive without colour and screen updates?
A session is made for commands that read and print text. Oda strips control sequences and normalises line endings, so colour codes and cursor movement do not come through, and a program that draws a full-screen interface is outside this design.
Does what a session sets up carry into the next send?
Yes. The working folder, exported variables, defined functions and any program the session left running all persist from one send to the next. Only the end of the session clears them.