# fatmux

<img src="./app/web/static/logo_nobg_fm.svg" alt="fatmux logo" width="160" />

Browser-first local workspace for project terminals, source control, and Claude/Codex chat sessions.

## For Users

fatmux is a local web app for working inside a project folder without leaving the browser. It gives you:

- Per-project terminals backed by `node-pty`
- Git tools for status, diffs, staging, commits, branches, fetch, pull, and push
- Claude Code and Codex CLI chat sessions wired into the workspace
- A local SQLite-backed data store for projects, terminals, agent sessions, messages, and raw events

### Install And Run

The published package exposes a `fatmux` CLI.

```sh
npx fatmux
```

By default, fatmux binds to `0.0.0.0` and stores its data in `~/.fatmux`.

If port `4173` is already in use, fatmux will automatically try the next available port and print the selected URL in the startup logs.

If you want to control the data directory explicitly:

```sh
FATMUX_HOME="$HOME/.fatmux" npx fatmux
```

If you want to override the bind host through the environment, use `FATMUX_HOST`:

```sh
FATMUX_HOST=127.0.0.1 npx fatmux
```

### Running In LXC, Docker, VMs, Or Remote Hosts

fatmux binds to all interfaces by default. It will log the final URL, the selected port, and whether it had to move away from the requested port because another process was already listening there.

If you want to restrict it to local-only access, start it explicitly on loopback:

```sh
npx fatmux --host 127.0.0.1
```

### What You Need

- Node.js that satisfies the repo `engine-strict` setting
- `npm`
- Optional: `claude` and `codex` CLIs if you want agent chat integration

Check the agent CLIs if you plan to use them:

```sh
claude --version
codex --version
```

### Accessing fatmux Over Tailscale

If you want remote access, you can either use the default `0.0.0.0` bind or expose the local port through Tailscale.

#### Option 1: `tailscale serve`

```sh
npx fatmux
tailscale serve https / http://127.0.0.1:4173
```

#### Option 2: Direct Tailnet Access

Use Tailscale SSH, port forwarding, or another trusted tailnet path to reach the local port.

## Repository Layout

```text
app/web      SvelteKit frontend
app/server   Node HTTP/WebSocket runtime
app/shared   Shared TypeScript types and schemas
scripts      Local dev and release scripts
```

## Development

### Install

```sh
npm install
```

### Run Locally

```sh
npm run dev
```

`npm run dev` starts the local workspace manager defined in [`scripts/dev.sh`](./scripts/dev.sh), with:

- shared type-checking in `app/shared`
- the server in `app/server`
- the web UI in `app/web`

### Build

```sh
npm run build
```

### Check

```sh
npm run check
```

### Test

```sh
npm test
```

### End-to-End Tests

```sh
npm run test:e2e
```

## Release Workflow

fatmux uses date-based CalVer with a hotfix suffix:

```text
YYYY.M.D-N
```

Examples:

- `2026.4.30`
- `2026.4.30-1`
- `2026.4.30-2`
- `2026.5.1`

Release numbering rules:

- The base version is the current date in local time
- If a version for today already exists, the suffix increments
- On a new day, numbering resets to the new date without a suffix

### Release Command

The release flow is implemented as an npm script:

```sh
NPM_TOKEN=your_token npm run release
```

That script does the following:

1. Runs `npm run release:version`
2. Computes the next date-based version from the repo’s package manifests
3. Runs `npm publish --tag latest`

### Authentication For Publishing

Publishing uses the npm token from the environment:

```ini
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
```

Set `NPM_TOKEN` in your shell before running the release command.

### Notes On Publish Artifacts

- The root package is the published CLI package
- The workspaces are part of the repo and are not separately published by the default release command
- `fatmux.js` is the CLI entrypoint

## Package Structure

- [`package.json`](./package.json) defines the CLI package, workspace orchestration, and release scripts
- [`app/server/package.json`](./app/server/package.json) contains the server workspace
- [`app/shared/package.json`](./app/shared/package.json) contains shared types and schemas
- [`app/web/package.json`](./app/web/package.json) contains the browser UI

## Working On The Project

### Common Local Commands

```sh
npm run dev
npm run check
npm test
npm run build
```

### Release Checklist

- Confirm `NPM_TOKEN` is set
- Run `npm run release`
- Verify the published version
- Commit and push the manifest changes if you want the release bump recorded in git

### Versioning Files

The release script updates these manifests:

- [`package.json`](./package.json)
- [`app/shared/package.json`](./app/shared/package.json)
- [`app/server/package.json`](./app/server/package.json)
- [`app/web/package.json`](./app/web/package.json)

## Implementation Notes

- The app stores persistent state in SQLite under `~/.fatmux`
- The web UI is SvelteKit-based
- The server is a Node runtime with HTTP and WebSocket endpoints
- Agent support uses locally installed CLI tools rather than vendor API keys stored in fatmux

## Troubleshooting

- If `npm publish` refuses the version, check whether the version has a prerelease suffix and whether the `--tag` flag is set
- If agents are missing, verify `claude` and `codex` are available on `PATH`
- If the app does not start, confirm your Node version satisfies the root `engine-strict` setting
