Repositories¶
The workspace aggregates your projects as git submodules under the repositories/ directory.
For AI tools with hook support, each submodule’s git state is automatically reported to the agent at session start.
The submodule model¶
Git submodules are pinned to specific commits. When someone clones the workspace, they get the exact versions that were last committed. During daily work, you work with the latest code inside each submodule - the pinned commits just serve as a baseline for cloning and CI.
The workspace periodically updates these pins to keep them reasonably current. This should be done as a dedicated action, not as a side effect of other work - otherwise unrelated submodule reference changes end up polluting your commits.
Adding repositories¶
Tracking a different branch¶
By default, submodules track main. To track a different branch, set branch in .gitmodules:
[submodule "repositories/backend"]
path = repositories/backend
url = git@github.com:org/repository.git
branch = develop
Then update:
Repository status reporting¶
Requires hook support
Automatic status reporting only works with AI tools that support session hooks.
Other tools can still use the workspace, but won’t receive automatic repo status context.
At session start, the session-start script checks each submodule’s git state and injects it into the agent’s context:
<repository-status>
<repo path="repositories/backend"
branch="main"
default-branch="main"
uncommitted-changes="false"
behind="0" />
<repo path="repositories/frontend"
branch="feature/new-ui"
default-branch="main"
uncommitted-changes="true"
behind="3" />
</repository-status>
Status fields¶
path- Submodule path relative to workspace root
branch- Current branch (or
detached @ <sha>for detached HEAD) default-branch- Auto-detected default branch (see detection logic below)
uncommitted-changes- Whether there are staged, unstaged, or untracked changes
behind- Commits behind the remote tracking branch (
unknownif offline)
With this, agents can warn about uncommitted changes, suggest pulling when behind, and understand which branch they’re working on.
Point-in-time snapshot
Repository status is captured once at session start and cached for the session’s lifetime. It may become stale if repo state changes during the session — for example, if branches are switched externally, another agent modifies the workspace, or the session runs long enough for remote refs to diverge.
Agents are instructed to verify repo state with git commands before branch switches or destructive operations. See Session Hooks — Limitations for more details.
Default branch detection¶
The default branch for each submodule is auto-detected at session start using a waterfall strategy:
- Git remote HEAD ref –
git symbolic-ref refs/remotes/origin/HEAD(accurate when present, but often missing in submodules) .gitmodulesbranch field – per-submodulebranchsetting (the recommended way to configure non-standard defaults)- Heuristic – checks if
origin/mainororigin/masterexists as a local remote ref - Fallback – defaults to
mainwith a warning printed to stderr
If a submodule uses a non-standard default branch (e.g., develop, trunk), set the branch field in .gitmodules for that submodule. This ensures correct detection regardless of the local git state.
Configuration¶
include_workspace_root- Default:
false- Also report status for the workspace root repo itself
Commit and push workflow¶
When making changes inside a submodule, always push the submodule before the parent. If the parent is pushed first, other users (and CI) will have submodule references pointing to commits that don’t exist on the remote yet.
Example workflow
Updating pinned commits¶
To update submodule pins to the latest remote commits:
This changes the pinned commit references in the parent repo. Commit and push these changes as a standalone commit - don’t mix them with unrelated work.
Tip
This is a good candidate for a periodic automated job (e.g., a scheduled CI workflow that opens a PR with updated submodule pins).
Other useful commands¶
# Initialize submodules after cloning (checks out pinned commits)
git submodule update --init --recursive
# Check current repository status (same output agents see at session start)
uv run .ai-workspace/scripts/session-start.py
Troubleshooting
- Commits in detached HEAD - Run
git checkout -b <branch>inside the submodule, thengit push -u origin <branch> - Forgot to push submodule before parent - Just push the submodule now; the parent reference is already correct
- Submodule update fails with conflicts - Reset and retry:
git submodule foreach --recursive git reset --hard && git submodule update --init --recursive - Status shows “unknown” for behind count - No network connection or no remote tracking branch; run
git fetchinside the submodule