Skip to main content
Tutorials Last updated: 11 March 2026

Projects and branches

This tutorial shows you how to register repos as projects and run tasks on feature branches — all from Telegram, without touching a terminal. Jump between re...

This tutorial shows you how to register repos as projects and run tasks on feature branches — all from Telegram, without touching a terminal. Jump between repos from wherever you are; your machine handles the checkout.

What you’ll learn: How to target repos from anywhere with /<project-alias>, and run on branches with @branch.

The problem

So far, Untether runs in whatever directory you started it. If you want to work on a different repo, you have to:

  1. Stop Untether
  2. cd to the other repo
  3. Restart Untether

Projects fix this. Once you register a repo, you can target it from chat—even while Untether is running elsewhere.

1. Register a project

Navigate to the repo and run untether init:

cd ~/dev/happy-gadgets
untether init happy-gadgets

Output:

saved project 'happy-gadgets' to ~/.untether/untether.toml

This adds an entry to your config (Untether also fills in defaults like worktrees_dir, default_engine, and sometimes worktree_base):

=== “untether config”

```sh
untether config set projects.happy-gadgets.path "~/dev/happy-gadgets"
```

=== “toml”

```toml
[projects.happy-gadgets]
path = "~/dev/happy-gadgets"
```

Project aliases are also Telegram commands The alias becomes a /command you can use in chat. Keep them short and lowercase: myapp, backend, docs.

2. Target a project from chat

Now you can start Untether from another repo. If you don’t specify a project, Untether runs in the directory where you launched it.

cd ~/dev/your-project
untether

And target the project by prefixing your message:

You /happy-gadgets explain the authentication flow

Untether runs the agent in ~/dev/happy-gadgets, not your current directory.

The response includes a context footer:

Untether dir: happy-gadgets
codex resume abc123

That dir: line tells you which project is active. When you reply, Untether automatically uses the same project—you don’t need to repeat /happy-gadgets.

3. Set up worktrees

Worktrees let you run tasks on feature branches without touching your main checkout. Instead of git checkout, Untether creates a separate directory for each branch.

Add worktree config to your project:

=== “untether config”

```sh
untether config set projects.happy-gadgets.path "~/dev/happy-gadgets"
untether config set projects.happy-gadgets.worktrees_dir ".worktrees"
untether config set projects.happy-gadgets.worktree_base "main"
```

=== “toml”

```toml
[projects.happy-gadgets]
path = "~/dev/happy-gadgets"
worktrees_dir = ".worktrees"      # where branches go
worktree_base = "main"            # base for new branches
```

Ignore the worktrees directory Add .worktrees/ to your global gitignore so it doesn’t clutter git status:

echo ".worktrees/" >> ~/.config/git/ignore

4. Run on a branch

Use @branch after the project:

You /happy-gadgets @feat/new-login add rate limiting to the login endpoint

Untether:

  1. Checks if .worktrees/feat/new-login exists (and is a worktree)
  2. If the branch exists locally, it adds a worktree for it
  3. If the branch doesn’t exist, it creates it from worktree_base (or the repo default) and adds the worktree
  4. Runs the agent in that worktree

The response shows both project and branch:

Untether dir: happy-gadgets @feat/new-login
codex resume xyz789

Replies stay on the same branch. Your main checkout is untouched.

5. Context persistence

Once you’ve set a context (via /<project-alias> @branch or by replying), it sticks:

You /happy-gadgets @feat/new-login add tests

Untether dir: happy-gadgets @feat/new-login

reply to the bot’s answer also add integration tests

Untether dir: happy-gadgets @feat/new-login

The dir: line in each message carries the context forward.

6. Set a default project

If you mostly work in one repo, set it as the default:

=== “untether config”

```sh
untether config set default_project "happy-gadgets"
```

=== “toml”

```toml
default_project = "happy-gadgets"
```

Now messages without a /<project-alias> prefix go to that repo:

You add a health check endpoint

Goes to happy-gadgets automatically.

Putting it together

Here’s a typical workflow:

untether

You /happy-gadgets review the error handling

You /happy-gadgets @feat/caching implement caching

Untether dir: happy-gadgets @feat/caching

You also add cache invalidation

You /backend @fix/memory-leak profile memory usage

You /happy-gadgets bump the version number

All from the same Telegram chat, without restarting Untether or changing directories.

Project config reference

Full options for [projects.<alias>]:

KeyDefaultDescription
path(required)Repo root. Expands ~.
worktrees_dir.worktreesWhere branch worktrees are created (relative to the project path).
worktree_basenullBase branch for new worktrees. If unset, Untether uses origin/HEAD, the current branch, or master/main (in that order).
default_enginenullEngine to use for this project (overrides global default).
chat_idnullBind a Telegram chat/group to this project.

Troubleshooting

“unknown project”

Run untether init <alias> in the repo first.

Branch worktree not created

Make sure the worktrees directory (default .worktrees) is writable. If you’ve customized worktrees_dir, verify that path exists or can be created.

Context not carrying forward

Make sure you’re replying to a message with a dir: line. If you send a new message (not a reply), context resets unless you have a default_project.

Worktree conflicts with existing branch

If the branch already exists locally, Untether uses it. For a fresh start, delete the worktree and the branch, or pick a new branch name.

Next

You’ve got projects and branches working. The final tutorial covers using multiple engines effectively.

Multi-engine workflows →

Was this helpful?

Related Articles