# The terminal, scripts and the file browser

Open a shell into a project's container, run named scripts and keep their output, and browse the container's files, from the desktop, a browser or a phone.

Every project in Borago Board runs in its own container, and three controls let you into it without leaving the board. The terminal is an interactive shell in tabs. Scripts are named commands you run with one press or that run when the container starts. The file browser lists the container's files so you can point the planning chat at one. All three run on the machine that hosts the container, which is your desktop, and the first two can be asked for from a browser or a phone while that desktop is online.

## Goal

A shell open in the project's container, a script that runs on demand and at every start, and a file from the container referenced in a chat message.

## Before you start

- A project whose container is running, see [Creating a project](/docs/guides/creating-a-project/). The terminal and the file browser need the container up. A script needs the container it targets up.
- For the terminal and scripts from the cloud browser or the phone, the desktop app open with cloud sync on, see [Cloud sync, browser and phone](/docs/guides/cloud-sync-browser-and-phone/).

## Steps

1. **Open a terminal.** Press **Terminal** in the board's filter bar, a row of the same name in the menu on a phone. The button is disabled with a reason in its tooltip when the container is not running, when its status is being re-checked, while a restart or rebuild is recreating it, or when the desktop is not connected. A panel opens, maximised over the board, with a shell already running in the container's working directory. That is the project's code, the `/app` folder in a generated container. The shell is bash where the image has it, otherwise sh, with a prompt that shows the working directory. The folder icon in the panel's header hides the directory from the prompt and shows it again.

2. **Work in tabs.** The **+** button in the tab strip, **New terminal tab**, opens another shell in the same container. Each tab is its own shell with its own history. A tab's **×**, **End this shell**, ends that one shell. A tab whose shell has exited stays in the strip, and clicking it starts a fresh shell in its place.

3. **Hide the panel without ending anything.** The **×** at the top right, **Hide terminal**, and the Escape key close the panel and keep every shell running. Reopening from the Terminal button brings the tabs back with their scrollback and the last active one selected. While any tab is live the Terminal button reads **Terminal (connected)** and glows. The header also offers **Maximise**, **Restore to the corner**, which docks the panel small so the board stays usable, and **Detach into its own window**, offered where the browser supports it, which floats the panel in a small window of its own carrying the same sessions. Dragging the header moves the docked panel.

4. **End the sessions.** The power icon, **End all sessions**, ends every tab's shell at once. A shell also ends when it exits on its own, when the container stops or is recreated, and when the app or the browser tab closes. A restart or rebuild of the container kills the shells inside it, and the tab shows that it ended.

5. **Copy, paste and open links.** Select text by dragging. **Ctrl+Shift+C** copies the selection and **Ctrl+Shift+V** pastes, with Cmd in place of Ctrl on a Mac. Plain Ctrl+C stays the interrupt. The right-click menu offers **Copy**, **Paste** and **Select All**. Web addresses in the output are links, both plain ones and the ones a tool prints as real terminal links. A plain click does nothing. **Ctrl+click** or **Cmd+click** opens the link, as does **Open Link** in the right-click menu, always in your system browser and never inside the app.

6. **Know what the shell sees.** Every tab gets the project's environment variables, the git credential and commit identity, and the Docker connection when container management is on, exactly what a task run, a script and a flow get. See [Secrets and environment variables](/docs/guides/secrets-and-environment-variables/). The terminal keeps no record. Nothing you type or see is stored by the board. From the cloud browser or the phone, the keystrokes and the output travel over the relay through the cloud to your desktop.

7. **Add a script.** Open the project dialog with **Edit project** and go to the **Scripts** tab. On an empty tab, **Add startup script** creates one named **Startup** with its trigger set to Startup. Otherwise press **+ Add script**. Each script has a **Script name**, a **Container** list where the project's own container is the default and any sibling container of the project can be picked, a **Trigger** of **Manual** or **Startup**, and the commands. **Import** creates a script from a text file on your computer, and the export button beside a script saves it as a `.sh` file. **Insert file path** opens the file browser and inserts the path you pick. The play button on a card runs the text as it is right now, saved or not, and shows its output under the editor, which is how you test it before saving. Press **Save** to keep the list. A project holds up to 25 scripts of up to 20,000 characters each, with unique names.

![The Scripts tab of the project dialog with a Startup script and two Manual scripts, each with its container and trigger.](/images/docs/terminal-scripts-and-files-7.webp)

8. **Run a script.** Press **Scripts** in the board's filter bar, or the row of that name in the phone's menu. The dialog lists every script with a **Startup** or **Manual** badge, the container it targets, a green play button and a chevron. The play button runs it. While it runs the button turns into a red stop button, which ends it. The chevron unfolds the script's **Commands** and its **Output**. A run that starts, from any device or by itself at a container start, unfolds its own row. **Edit scripts** at the bottom opens the Scripts tab of the project dialog, because this dialog runs scripts and that tab edits them. A backdrop click does not close this dialog, since closing it discards the output. Use the **×** or Escape.

![The Scripts dialog listing Startup, Run tests and Seed demo data, each with a Startup or Manual badge and a run button.](/images/docs/terminal-scripts-and-files-8.webp)

9. **Read and keep the output.** The **Output** panel streams while the script runs and ends with a status, **exited** and the exit code, **stopped** when you stopped it, or **error** with the reason, plus how long it took. The output is never stored. It lives only in the panel of the board that was open, and a dialog opened part-way through a run shows only what the server still had buffered. When a run has finished, a **Copy output** button appears beside the status and copies the whole run, not only what is on screen. When the copied text is not the whole run, it says so at the top. A script that fails raises a notice in the bell, which opens the project on its Scripts tab. A clean exit and a stop you asked for raise nothing. A script that is still running when the app closes keeps going in the container. When the app starts again, opening the Scripts dialog picks it up. The row shows the stop button again, and the output carries on from its most recent part under a line that says it was reattached. A restart or rebuild of the container ends a running script, and its status then reads **stopped**, not failed.

10. **Rely on the startup script.** A script with the **Startup** trigger runs by itself every time its container starts, after any git clone, in list order, one after another. A failing one does not stop the ones after it. It can still be run by hand from the Scripts dialog at any time. Put installs, migrations and seeds there, because a restart or rebuild rebuilds the container from its Dockerfile and anything installed by hand is gone. Startup scripts run for the container that started, including a sibling container started from the project's Containers tab. Stopping a container runs nothing.

11. **Browse the container's files from the chat composer.** Open the planning chat with **Plan tasks with AI** and press **Insert**, beside the **Send** button under the message box. The dialog **Insert a reference** has two tabs, **Conversation** and **File or folder**. The second is an explorer over the container's working directory, one level at a time, with breadcrumbs, **Up one level**, and one row per entry. Clicking a file inserts a reference to it into your message. Clicking a folder opens it, and the **Insert** button on its row references the folder instead. The header button reads **Insert this folder** inside a folder and **Insert the whole project** at the root, which lets the chat read the project and find things itself. The dialog stays open so you can pick several, counts what it added, and closes with **Done**. What it inserts is a mention starting with `@/`, the same thing you can type by hand.

12. **Know where the browser works.** The explorer asks the board it is open on to list the container. It works in the desktop app and in a browser on the local network, where that board is the desktop. From the cloud browser or the phone it reads **Files live on the machine that runs this project's container. Open this board in the desktop app to browse them.** A file mention typed by hand, such as `@/src/` for a folder or a file path after `@/`, still works from the phone, because the whole chat turn runs on your desktop where the container is. When the container is stopped the explorer says so and points at the project's Containers tab.

13. **Use all of it from a browser or a phone.** On a browser on your local network, the terminal, scripts and the file browser all talk to the desktop directly. From the cloud browser or the phone, the terminal and the scripts are relayed to your desktop. **Terminal** and the play buttons are shown there and disabled while the desktop is not connected. The scripts dialog's tooltip reads **Scripts run on the machine hosting the containers - open your desktop app (with cloud sync on)** and the terminal's reads **Your desktop app is not connected. Open it (with cloud sync on) to use this.** Script output started anywhere, at your desk or by a container start, streams to the phone too. Walking out of signal during a run does not stop it. The file browser is the exception and stays desktop and local network only.

## If it did not work

- **The Terminal button is disabled.** Read its tooltip. It names the container that is not running, in which case start the container from the project's controls. It says the status is being re-checked, in which case wait a few seconds. It names a restart or rebuild in flight, in which case the button comes back when the container is up. On the cloud browser or the phone it says the desktop app is not connected.
- **A paste arrives twice or not at all.** Use **Ctrl+Shift+V** or the right-click **Paste**, not Ctrl+V. Plain Ctrl+V is not wired to the terminal, and Ctrl+C interrupts the running command instead of copying.
- **A script says its container is not one of this project's, or is missing here.** A script targets a container by name. When the project names a sibling that this machine has not created, the run is refused with a sentence saying which half is missing. Pick the project's own container in the script's **Container** list, or start that sibling from the Containers tab first.

Related: [Creating a project](/docs/guides/creating-a-project/), [Secrets and environment variables](/docs/guides/secrets-and-environment-variables/), [Chat to tasks](/docs/guides/chat-to-tasks/), [Cloud sync, browser and phone](/docs/guides/cloud-sync-browser-and-phone/), [Container management](/docs/guides/container-management/)
