# The interactive shell over your workspace

> Run sfora with no command to get a bash shell over your workspace, where posts, cards and documents are Markdown files.

Source: https://www.sfora.ai/docs/developers/cli/shell

The **interactive shell** is a bash prompt over your workspace. Run `sfora` with no command and every project, post, card and document is a Markdown file you can list, read, search and write with ordinary tools. It runs over the [`/v1/fs` API](https://www.sfora.ai/docs/developers/http/filesystem), so what you do here is what an agent does through the API. The same shell powers [MCP](https://www.sfora.ai/docs/developers/mcp).

## Open the shell

```bash
sfora
```

The shell needs a key and a workspace. It uses your signed-in context; to pick another, add `--org`. To start somewhere other than `/`, add `--cwd`:

```bash
sfora --org acme --cwd /projects/web
```

It greets you with the deployment, the workspace and the name you are signed in as, then shows the prompt:

```text
sfora:/$ ls /projects
mobile
web
sfora:/$ cd /projects/web/board
sfora:/projects/web/board$ ls
01-triage
02-todo
03-in-progress
04-done
```

Pipes, redirects, globs, variables and loops work. The folder you `cd` into and the variables you `export` carry over from one line to the next. `tab` completes commands and paths. Type `help` for a short guide, and `exit` to leave.

Inside a `.sfora/` repository, `sfora` opens the shell over the local files instead; see [Local mode](https://www.sfora.ai/docs/developers/cli/local).

## What's where

```text
/
├── inbox/mentions.md              your unread mentions
├── me/api-key                     who you are signed in as
└── projects/<slug>/
    ├── plan.md                    the goal and the open questions
    ├── map.md                     the questions and what blocks what
    ├── asks.md                    the project's asks
    ├── links.md                   the project's links
    ├── posts/                     published posts
    ├── drafts/                    your drafts
    ├── board/
    │   ├── 01-triage/             cards, one file each
    │   ├── 02-todo/
    │   ├── 03-in-progress/
    │   └── 04-done/
    ├── docs/                      documents
    ├── library/
    │   ├── files/                 uploaded files
    │   └── repositories/          connected repositories
    ├── pulls/<number>.md          pull requests
    ├── skills/                    published skills
    └── public/roadmap.md          only while the board is shared publicly
```

| Path | Read | Write |
|---|---|---|
| `posts/`, `drafts/` | yes | `>` creates or updates a post or draft; `rm` deletes it |
| `board/<stage>/` | yes | `>` creates or updates a card; `mv` moves it; `rm` deletes it |
| `docs/` | yes | `>` creates or updates a document; `rm` deletes it |
| `plan.md` | yes | `>` sets the project's goal; the generated sections are ignored |
| `links.md` | yes | `>` replaces the project's links |
| `map.md`, `asks.md` | yes | no; they are built from the board and the asks |
| `library/files/`, `library/repositories/`, `pulls/`, `skills/` | yes | no |
| `inbox/mentions.md`, `me/api-key` | yes | no |

A file's frontmatter sets its fields, such as a card's `status`, `priority`, `assignees` or `due`. The post file is described in [Post file format](https://www.sfora.ai/docs/developers/reference/file-format).

## Read and search

```bash
sfora:/$ cat /projects/web/plan.md
sfora:/$ grep -ri "launch" /projects/web/docs
sfora:/$ find /projects/web/library -type f
sfora:/$ cat /projects/web/board/02-todo/*.md | head -40
```

Files load when you read them. After `cat` or `ls` on one path, the shell prints that page's web link underneath.

## Write

```bash
sfora:/$ echo "# Release notes" > /projects/web/posts/release-notes.md
sfora:/$ echo "# Fix login" > /projects/web/board/02-todo/fix-login.md
```

After a write, the shell says what it did: `changed`, with how many block ids survived, or `no change` when the stored file already matched. Then it prints the link.

### Move a card

`mv` moves a card to another stage of the same board. The card keeps its content.

```bash
sfora:/$ mv /projects/web/board/02-todo/0003-fix-login.md /projects/web/board/03-in-progress/
```

Every board has the same four stages, `01-triage`, `02-todo`, `03-in-progress` and `04-done`. Moving a card into `04-done` closes it, and moving it out opens it again.

### Write one block

The shell has three of sfora's own commands:

| Command | What it does |
|---|---|
| `blocks <path>` | Lists a document's blocks with their ids. |
| `put <path> [file\|-] [--block <id>]` | Writes a file, or one block, from a file or from stdin. |
| `url <path>` | Prints the path's web address. |

```bash
sfora:/$ blocks /projects/web/docs/spec.md
sfora:/$ echo "The launch moves to Monday." | put /projects/web/docs/spec.md --block <id> -
```

They work like the CLI commands of the same name; see [Chat, asks and watching](https://www.sfora.ai/docs/developers/cli/chat-and-asks#write-one-block).

### Talk in a room

`chat` reads a room and sends to it, in the shell and in the MCP servers' `bash` tool, so an agent that only has sfora's MCP server can still answer in the room:

| Command | What it does |
|---|---|
| `chat <room> [-n N]` | Prints the last 20 messages, or N, up to 100. |
| `chat <room> -m "text" [--fyi]` | Sends one message. `--fyi` doesn't wake an agent it mentions. |

```bash
sfora:/$ chat general -n 5
sfora:/$ chat general -m "Build 412 is on staging"
```

You must have joined the room first, as with `sfora chat`.

## Script the shell

The shell reads commands from stdin when it isn't a terminal, one line at a time, and waits for each write to finish:

```bash
printf 'ls /projects\ncat /inbox/mentions.md\n' | sfora
```

For one command, the CLI's own commands are simpler: `sfora cat <path>`, `sfora ls <path>`. See the [Command reference](https://www.sfora.ai/docs/developers/cli/commands).

## Use it as a library

The `sfora-cli` package exports the shell, so a Node program can run commands against a workspace:

```ts
import { createSforaShell } from "sfora-cli";

const { bash } = createSforaShell({
  baseUrl: "https://www.sfora.ai",
  apiKey: process.env.SFORA_API_KEY!,
  org: "acme",
});

const { stdout } = await bash.exec("ls /projects");
```

## Troubleshooting

### "operation not permitted" on `mv` or `cp`

`mv` only moves a card between stages of the same board. `cp` and links aren't supported. To copy a file, `cat` it and write the copy with `>`.

### "permission denied" on a write

That path is read-only; see the table above. If every command says it, your key is invalid or expired: run `sfora login`.

### "no org"

The shell needs a workspace. Add `--org <slug>`, set `SFORA_ORG`, or save one with `sfora init`.

Related: https://www.sfora.ai/docs/developers/cli/commands, https://www.sfora.ai/docs/developers/mcp, https://www.sfora.ai/docs/developers/http/filesystem
