Skip to content

feat(minimald): implement RPC for creating sessions, index by session name also - #265

Merged
twitchyliquid64 merged 1 commit into
mainfrom
tom/scaffolding
Jun 1, 2026
Merged

feat(minimald): implement RPC for creating sessions, index by session name also#265
twitchyliquid64 merged 1 commit into
mainfrom
tom/scaffolding

Conversation

@twitchyliquid64

@twitchyliquid64 twitchyliquid64 commented May 29, 2026

Copy link
Copy Markdown
Member
  • Session names are now unique, and DiskLoader indexes by name also
  • Implements CreateSession RPC.

This is technically breaking the format of index.json, except there was never a path to write it before, so it should be empty.

Summary by CodeRabbit

  • New Features

    • Sessions can now be created remotely via the SSH RPC interface for programmatic session management.
  • Improvements

    • Session names must be unique; creating a session with a duplicate name is rejected.
    • Session storage and indexing improved for more reliable listing and lookups.
    • Session records missing an ID are now accepted and given a default ID.
  • Chores

    • Added a dependency used by session handling.
  • Tests

    • New/updated tests validate session creation, storage, and listing behavior.

@coderabbitai

coderabbitai Bot commented May 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds end-to-end session creation: persistent index and name-uniqueness in the sessions store, a manager actor create API, and an SSH oneshot CreateSession RPC with integration tests.

Changes

Session Creation Feature

Layer / File(s) Summary
Disk store index refactoring and name uniqueness
crates/sessions/src/store.rs, crates/sessions/src/lib.rs
Introduces a serializable Index (short_to_uuid, name_to_uuid). DiskLoader loads sessions/index.json, enforces unique record.name on create, updates short-dir collision checks, and rewrites list, find_by_uuid, and find_by_name to use the index; tests updated.
Record deserialization support
crates/sessions/src/lib.rs
Adds #[serde(default = "Uuid::nil")] to Record.id so deserialization tolerates a missing id.
Sessions manager create API
crates/minimald/src/sessions.rs
Adds ManagerMessage::CreateSession handling and ManagerHandle::create_session(record) which forwards to the store and returns the created Uuid.
SSH RPC CreateSession handler and dispatcher wiring
crates/minimald/src/rpc.rs
Adds CreateSession oneshot RPC request/response and handler that calls sessions_manager.create_session(). Wires CreateSession::NAME into dispatcher spawn logic, updates ListSessionsEntry derives, and adds an integration test validating create → GetSessionRecord → ListSessions.
Workspace dependency addition
crates/minimald/Cargo.toml
Adds bytes as a workspace dependency.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant SshDispatcher
  participant CreateSessionHandler
  participant SessionsManager
  participant DiskStore
  Client->>SshDispatcher: CreateSessionRequest(record)
  SshDispatcher->>CreateSessionHandler: spawn handler for CreateSession::NAME
  CreateSessionHandler->>SessionsManager: create_session(record)
  SessionsManager->>DiskStore: create(record)
  DiskStore->>DiskStore: enforce name uniqueness, insert into Index
  DiskStore-->>SessionsManager: Uuid
  SessionsManager-->>CreateSessionHandler: Uuid
  CreateSessionHandler->>Client: CreateSessionResponse(id)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • gominimal/minimal#235: Introduced the SSH oneshot RPC scaffolding and dispatcher plumbing that CreateSession plugs into.
  • gominimal/minimal#253: Earlier sessions/RPC scaffolding and store evolution that this PR extends with create and index changes.

Suggested reviewers

  • norrietaylor
  • evanspearman
  • 0chroma

Poem

🐰 I hopped through code to plant a seed,

A named session sprouted from a need,
From RPC call down to disk it trots,
The manager hums and checks the spots,
Now a UUID nest grows where it read.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main changes: implementing an RPC for creating sessions and adding name-based indexing.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/minimald/src/rpc.rs`:
- Around line 200-203: CreateSessionRequest's record field is private so
external clients cannot build the request; make the field public by changing the
struct field `record: sessions::Record` to `pub record: sessions::Record` in the
CreateSessionRequest definition (the same pattern used for other
request/response structs) so that code exercising the OneshotSshRpc
Serialize-bound Request can construct and serialize CreateSessionRequest.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1664f24e-050e-47ff-a68e-dbe25918c3e2

📥 Commits

Reviewing files that changed from the base of the PR and between c38eec4 and dca16e7.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • crates/minimald/Cargo.toml
  • crates/minimald/src/rpc.rs
  • crates/minimald/src/sessions.rs
  • crates/sessions/src/lib.rs
  • crates/sessions/src/store.rs

Comment thread crates/minimald/src/rpc.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
crates/minimald/src/rpc.rs (1)

359-399: ⚡ Quick win

Consider covering the name-uniqueness conflict path.

This test validates only the happy path. Since enforcing unique session names is the primary goal of this stack, a test that issues a second CreateSession with a duplicate name and asserts the RPC surfaces an error would guard the handler's error-propagation contract.

Want me to draft that conflict-path test?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/minimald/src/rpc.rs` around lines 359 - 399, Add a new test (or extend
create_session_shows_in_get_and_list) to exercise the name-uniqueness conflict
by calling the CreateSession RPC twice with the same sessions::Record.name via
CreateSessionRequest and asserting the second call returns an error;
specifically, call client.call::<CreateSession>(&CreateSessionRequest { ...
name: "my session" ... }).await again and assert the RPC surfaces a uniqueness
violation (match the returned error/result shape your RPC layer uses), ensuring
the test references CreateSession, CreateSessionRequest, and the original
session id/name for clarity.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/sessions/src/lib.rs`:
- Around line 21-23: Update the doc comment for the Record.id field to clearly
state that deserialized or caller-supplied ids may be Uuid::nil() and that the
store layer (Loader::create) will overwrite such incoming ids with a newly
generated id (Uuid::now_v7()); reference both Uuid::nil and
Loader::create/Uuid::now_v7 in the comment so callers know nil values are
expected and replaced by the store during creation.

---

Nitpick comments:
In `@crates/minimald/src/rpc.rs`:
- Around line 359-399: Add a new test (or extend
create_session_shows_in_get_and_list) to exercise the name-uniqueness conflict
by calling the CreateSession RPC twice with the same sessions::Record.name via
CreateSessionRequest and asserting the second call returns an error;
specifically, call client.call::<CreateSession>(&CreateSessionRequest { ...
name: "my session" ... }).await again and assert the RPC surfaces a uniqueness
violation (match the returned error/result shape your RPC layer uses), ensuring
the test references CreateSession, CreateSessionRequest, and the original
session id/name for clarity.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1380d9a5-27d9-48de-ac12-7228e020fa70

📥 Commits

Reviewing files that changed from the base of the PR and between cb1b680 and d1eb82d.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • crates/minimald/Cargo.toml
  • crates/minimald/src/rpc.rs
  • crates/minimald/src/sessions.rs
  • crates/sessions/src/lib.rs
  • crates/sessions/src/store.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/minimald/Cargo.toml
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/minimald/src/sessions.rs
  • crates/sessions/src/store.rs

Comment thread crates/sessions/src/lib.rs
.iter()
.map(|(short, id)| Self::Key {
session_uuid: *id,
dir_key: DaemonRelPath::try_new(short).unwrap(),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect this is something that's going to keep coming up. We probably want to newtype Uuid as SessionId (this would be good regardless) and either implement a to_daemon_rel_path on it.

We should probably also add new_unchecked constructors (with big warnings on them) for the path types and just be really careful about where we use them.

Don't think we can do From<SessionId> for DaemonRelPath since we were talking about moving the paths module to its own crate and the sessions crate will be downstream of that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slightly out of scope but we probably want to rename this method to keys which is more standard.

pub struct DiskLoader {
minimal_dir: DaemonAbsPath,
index: BTreeMap<String, Uuid>,
index: Index,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, is this going to be always kept in sync or is it going to be lazy? If lazy, we probably want to wrap it in RefCell so any future read-only methods don't need to take &mut self. Looks like it's kept in sync so far, just wanted to check.

}

impl Index {
pub fn insert(&mut self, short: String, uuid: Uuid, name: Option<String>) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, but do we want search to live in the index type as well?

@twitchyliquid64

Copy link
Copy Markdown
Member Author

Thanks! Given the dep from a later PR I'm going to merge this as-is and send a follow-up PR for the changes (newtype SessionId, keys() etc)

@twitchyliquid64
twitchyliquid64 merged commit a0271c0 into main Jun 1, 2026
8 checks passed
@twitchyliquid64
twitchyliquid64 deleted the tom/scaffolding branch June 1, 2026 16:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants