Skip to content

I0803 — Open a session and report its status

Implement lib/session.sh with `session start` and `session status`: one active session per worktree in .majordomus/state/session-current.yaml, its identity and git facts computed, a second start refused rather than silently replacing the first, and a status that reports the active session against current git or says plainly that none is open.

DONE wave 1 · p1 · implementation profile · runs alone

Part of M003 — A session is a durable envelope, and knowledge is compiled from what is already canonical.

Objective

Implement lib/session.sh with `session start` and `session status`: one active session per worktree in .majordomus/state/session-current.yaml, its identity and git facts computed, a second start refused rather than silently replacing the first, and a status that reports the active session against current git or says plainly that none is open.

Why

The active record is the anchor every later command reads. It has to refuse rather than overwrite, because an execution episode that silently replaces another one loses the boundary the whole object exists to draw.

Current state

There is no session command and no session state file. bin/majordomus dispatches its subcommands from a fixed case list.

Desired state

`majordomus session start` writes the active record atomically at mode 0600, records session_id, started_at, owner, an optionally supplied worker identity, and the computed repository_id, worktree, branch, start_head and start_working_tree. It refuses when a session is already open in this worktree and names the command that closes it. `session status` prints the open session with its divergence label, or reports absence. Both are dispatched from bin/majordomus and appear in its usage.

Scope

  • lib/session.sh
  • bin/majordomus
  • share/allow
  • docs/CLI.md
  • test/cases/60_session_lifecycle.sh

Out of scope

  • Closing a session
  • Any reading of the ledger
  • Knowledge

Dependencies

What waits on this

Acceptance criteria

  • The command has a section in docs/CLI.md, because the site generator refuses a dispatched command with none, and it documents only what is implemented
  • A session starts, the active record exists, and its identity fields match git
  • A second start is refused with a non-zero exit and names the closing command
  • A session started in one worktree does not appear as active in another
  • status reports absence as absence rather than as an error
  • The active record's unknown keys are rejected by an allowlist like every other Majordomus YAML file

Validation

  • bash test/run.sh 60_session_lifecycle
  • shellcheck -x -s bash lib/session.sh

Evidence required

  • session_opens

Evidence

coverstypecommandresultat commit
session_openstesttest/run.sh 60_session_lifecycle1 passed. The case proves identity is computed from git rather than authored, that absence is answered as absence and exit 0, that the record is mode 0600, that an unsupplied worker stays unrecorded rather than being invented, that a second open is refused with exit 15 and names the closing command, that a record whose worktree is another checkout is reported and does not block this one, that a corrupt record exits 10 rather than being read as no session, and that status writes nothing. The repository shellcheck gate passes at warning severity over the whole tree9c13909

Risk

One active session per worktree is the same rule current.yaml already has, and current.yaml is tracked, so it travels with the branch and appears active in a checkout that never started it. The session record has to record its worktree and be read with the same foreign-record rule.

Timeline

started
verified
completed
2026-09-04T16:29:23Z

Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.

Canonical record: .ai/repo/project/issues/I0803.yaml. Read it back with majordomus plan show I0803.