Skip to content

feat(profiles): support session-bound active profiles without global routing mutation #1064

Open

Description

@noxsystems

Before submitting

  • I searched open and closed issues and did not find a request for this feature.
  • I reviewed this request and removed credentials, tokens, private paths, hostnames, and other sensitive data.

Problem or opportunity

Concurrent Pi processes may need different active profiles while sharing the same machine or project. Today, /gentle:profiles updates shared configuration and materialized routing by default. Running work remains unchanged, but later subagent launches can observe another process's profile changes.

This affects ordinary terminals, terminal multiplexers, IDE panes, CI, and other environments. It is a Pi process/session configuration boundary rather than a host-specific integration concern.

Proposed outcome

Preserve the existing global profile mechanism and add an explicit, opt-in active-profile binding at the parent Pi session boundary.

The profile UI should distinguish actions conceptually equivalent to:

  • Use in this session — resolve and store a session-local profile binding and effective routing snapshot without mutating shared routing files.
  • Reload in this session — explicitly refresh that session's snapshot from the saved profile definition.
  • Set as global default — retain the existing global persistence and materialization behavior for future or unbound sessions.

Session-bound behavior should satisfy these invariants:

  • Concurrent parent sessions can select different profiles without rewriting each other's shared defaults or routing.
  • Switching profiles within one parent session updates only that session's binding.
  • New child launches inherit the parent's current effective snapshot.
  • Running and already-queued children retain the routing resolved when they were launched or queued.
  • Resuming a parent session restores its last session-bound profile and snapshot.
  • Editing a saved profile definition does not silently alter an already-bound session; refreshing it requires an explicit reload or re-selection.
  • Display the effective profile, scope, and configuration source.
  • Existing behavior remains unchanged when no session binding is selected.
  • Existing profile files require no migration.

A possible precedence model is:

explicit launch-local route
→ parent session-bound profile snapshot
→ project routing
→ global active profile
→ existing defaults

The exact command names and persistence mechanism can follow the maintainers' preferred configuration authority. The central invariant is that session-scoped selection must not mutate routing observed by unrelated concurrent parent sessions.

Suggested regression coverage:

  • two concurrent parent sessions using different profiles;
  • concurrent sessions in the same project;
  • switching one session while the other remains unchanged;
  • queued and running child stability;
  • future child inheritance after switching;
  • session resume;
  • explicit session reload after editing a saved profile;
  • unchanged behavior for sessions without a binding;
  • existing profile files loading without migration.

Relationship to the existing per-repository pins

The per-repository pin shipped in #1074 solves a narrower configuration boundary:

  • p writes a clone-local selection to <git-common-dir>/gentle-ai/profile-pin.json. It is isolated from other clones, but every worktree and every Pi session in that clone shares it.
  • P writes a repository declaration to <worktree-root>/.pi/gentle-ai/profile.json. It is intended as a shared repository or team default, so it is also shared by concurrent sessions using that worktree.
  • Both layers affect subagent routing at launch without rewriting the globally active routing. The clone-local p layer takes precedence over P, then routing falls back to the globally active profile.

Those pins solve parallel work across different repositories or clones. They do not allow two parent sessions in the same clone to select different profiles. If session A changes p, future child launches from session B observe the same clone-local selection. P is likewise a repository default, not a session override.

This request adds an independent layer above those defaults. A parent session should hold its own effective profile snapshot, children should inherit the snapshot of the parent that launched or queued them, and another session should remain unchanged. Because it is a snapshot rather than a shared profile-name lookup on every launch, later edits to the saved profile definition should require explicit reload or re-selection before affecting that bound session.

The resulting conceptual precedence is:

explicit launch-local route
→ parent session-bound profile snapshot
→ clone-local pin (`p`)
→ repository declaration (`P`)
→ global active profile
→ existing defaults

The existing p and P behavior should remain unchanged. They become defaults for sessions that have no explicit session binding.

Alternatives considered

Separate GENTLE_PI_CONFIG_HOME and GENTLE_PI_AGENT_HOME / PI_CODING_AGENT_DIR roots provide supported path isolation, but require external environment setup and duplicated configuration rather than a native session binding.

Project-local routing helps separate projects but does not solve concurrent sessions in the same project. Switching the shared active profile is not session isolation.

Additional context

Related: #1025 proposes authorized routing classes selected for individual child launches. This request concerns a human-selected active profile bound to the parent Pi session and inherited as its default routing context. The two features can coexist if launch-local routes have explicit higher precedence.

Coordinate precedence with #600 and preserve the path-isolation support established by #575 and #633.

Activity

  1. JeanN00B commented on Sep 16, 2026

    @JeanN00B

    Additional concurrency finding from a source and runtime audit:

    The global scope is documented and should remain backward-compatible, but concurrent profile operations are not serialized. profiles.json and Pi orchestrator settings use per-file temp-and-rename writes, while models.json is written directly. Applying a profile spans the profile store, models.json, materialized subagents.json or agent frontmatter, and Pi settings without a cross-file lock or transaction. Two processes can therefore read stale panel state, overwrite each other's active marker or routing, or leave the stores representing different profiles. ppi does not solve this by itself because it only sets PI_CODING_AGENT_DIR; Gentle's GENTLE_PI_CONFIG_HOME remains shared, and same-cwd project routing remains shared too.

    A narrow disposable two-process repro confirmed the shared-store behavior: process A wrote profile A, process B read A; after B wrote profile B, A read B. Using distinct GENTLE_PI_CONFIG_HOME values kept the stores isolated. Suggested coverage includes concurrent apply, create, update, and rollback operations, stale panel state, and shared versus isolated config homes. This is distinct from the session-bound behavior requested here, but likely worth considering in the same design.

  2. daandradec commented on Sep 16, 2026

    @daandradec

    +1 on this — here is a concrete workflow that needs the session-bound invariant, in case it helps with prioritization.

    Use case

    I run two pi sessions side by side in two completely separate project directories, with two profiles created via /gentle:profiles: one routed to OpenAI, one to DeepSeek. Project A is the OpenAI work, project B is the DeepSeek work.

    What I need from this feature is exactly one of the invariants already listed: selecting the DeepSeek profile in session B must leave session A on OpenAI. The two that matter most for this workflow are:

    • "Concurrent parent sessions can select different profiles without rewriting each other's shared defaults or routing."
    • "New child launches inherit the parent's current effective snapshot."

    What happens today

    The active marker is machine-global, so choosing a profile in one session changes the routing that every other concurrent session resolves for its next subagent launch. In the two-project setup above, after activating DeepSeek in project B, /gentle:models in project A had moved to DeepSeek as well.

    The per-repository pin shipped in #1074 (p on a profile) covers the two-separate-repositories case and is the right workaround today. It does not cover the general case this request is about: concurrent sessions that share one repository, or a single session where I want a different profile than the repository default without touching shared state.

    Environment

    • Pi: 0.85.1 (@earendil-works/pi-coding-agent)
    • gentle-ai CLI: 2.8.2
    • gentle-pi: source checkout v2.5.0-179-g8ec0f98b (package.json 2.5.0)
    • OS: macOS

    No new mechanism to propose — the precedence model in the description already handles this case. Happy to test a branch once session binding lands.

  3. LCubero commented on Sep 17, 2026

    @LCubero

    Confirmed a Windows reproduction that adds one specific failure mode to this request: /gentle:profiles persists the profile's orchestrator entry to Pi's global defaultProvider, defaultModel, and defaultThinkingLevel, but it does not update the model or thinking level of the current parent session.

    The paths resolve correctly on Windows, with no agent/config-home overrides and no project-local .pi/settings.json, so this does not appear to be a Windows path issue. The live session state can diverge from both settings.json and the active profile. Also, s snapshots the orchestrator through readOrchestratorSettings(...), which captures the global defaults rather than ctx.model and ctx.thinkingLevel from the running session.

    For the proposed Use in this session behavior, please include both sides explicitly: capture the live parent model/effort from the session, and apply the selected profile through Pi's current-session APIs (pi.setModel() and pi.setThinkingLevel()). Persisting default* should remain the separate global-default action.

  4. AitorDuran commented on Sep 27, 2026

    @AitorDuran

    A concrete parallel-work scenario for this request:

    • Session A in one worktree uses an OpenSource profile.
    • Session B in another worktree (or even a different project) uses an OpenAI profile.
    • Session C uses a Claude-Hybrid profile, with Claude, OpenAI, and NaN models assigned to different roles.

    The reported behavior is that selecting a profile in one session changes the effective profile in other already-running sessions, even across projects. That makes it impractical to run these independent model/provider mixes in parallel, although each session can already use a different orchestrator.

    Desired behavior: selecting a profile changes only the current session's effective model routing. Other live sessions should retain their chosen profiles regardless of whether they share a repository, belong to separate worktrees, or run in unrelated projects. Any repository-level default for new sessions should not silently rewrite existing sessions.

  5. Denver2828 commented on Sep 27, 2026

    @Denver2828

    Adding a concrete 3.7.0 use case for this session-bound routing proposal: please distinguish saved defaults from the dispatching parent's live model and thinking level. This is a UX/contract clarification and opt-in enhancement request, not a confirmed regression.

    Observed with Gentle Agents (subagent_run): the parent session recorded openai-codex/gpt-6-astra with low thinking before dispatch, but an unpinned gentle-ai-verify launched with openai-codex/gpt-5.5 / medium, matching the saved Pi default. No verifier model assignment was present in the agent definition or saved routing. Child runtime metadata confirmed the difference.

    The installed 3.7.0 implementation explains the result:

    • resolveAgentProfile resolves profile, then agent definition, then configured defaults. It does not take the parent's live model as an input.
    • childArguments omits --model when unresolved, leaving the child to use Pi startup defaults.
    • The versioned documentation says “Inherit active/default model”, while the repository-pin section describes inheritance as “their own definition, then the default model”. The former is easy to interpret as the live parent selection, but I did not find an explicit promise of that behavior.

    For the design here, could we make these separate, user-owned choices: use saved routing/defaults (unchanged existing behavior) and inherit the parent session's live model + thinking (explicit opt-in)? A session-bound profile snapshot and a live /model selection are not necessarily the same thing, so their interaction and precedence should be stated rather than inferred. Explicit agent assignments should remain predictable, with the resolved provider/model/thinking and source visible before execution. The intended benefit is predictable cost and capability, not forcing every role onto one model.

    Suggested coverage: parent selection differs from saved defaults; explicit role assignments; parent changes after queueing (queued tasks retain their resolved snapshot); and unchanged behavior without opt-in. This can fit the design discussion in this issue alongside #1025 rather than creating another overlapping tracker. No claim is made that current main has been reproduced or that the existing behavior violates a documented live-inheritance contract.

  6. matraket commented on Sep 29, 2026

    @matraket
    Contributor

    I ran into this problem while working with two sessions in the same repo: one on a frontier-model profile and one on a local/open-source profile to translate a documentation corpus. I spent quite some time analyzing the best way to solve it, and along the way I came across this issue and its comments, as well as #1240 and #1478, which tackle the same problem from different angles.

    This comment is an attempt to consolidate my approach with the issue and with everything contributed in the thread. To avoid arguing from assumptions, I traced the code on current main (5cc591f) and on Pi 0.87.1. Everything below is verified against that code unless I say otherwise.

    Where I agree and where I don't

    I agree with @noxsystems on the central invariant: selecting a profile in one parent session must not change what any other session launches. I also agree with the precedence (launch-local route, then session, then p, then P, then global), with children inheriting the parent's selection, with running and queued children keeping what they resolved (this already holds today: the queue stores the fully resolved request, agents-runner.ts:349), with resume restoring the selection, and with no migration of existing files.

    I disagree with @noxsystems on making the session binding opt-in. If Enter keeps mutating global state and "use in this session" is a separate action, the default path is still the one that silently moves every other session. The p and P keys already establish the right mental model: Enter picks a profile for this session, and the persistent layers are explicit keys. I propose that Enter becomes session-only and that a new G key sets the global default, next to p (clone) and P (repository).

    On snapshot versus following the profile by name, I don't have a settled position. I see arguments for both. Simplicity favors storing only the name: in my opinion, the most common reason to edit a profile is tuning it (an agent is under- or over-powered), and in that case it makes sense for every session using it to get the adjustment without a reload in each one. Avoiding silent changes favors the snapshot + reload that @noxsystems proposes. I think both options are reasonable and only real usage will tell which one was right, so either works for me. What does seem important to me is not letting this decision block the rest: it is a minor detail compared with the current situation, where it is practically impossible to parallelize work that needs different capability levels. Whichever option is chosen, children that are already running or queued are unaffected (this already holds today), and if the bound profile is deleted, the session falls back to the next layer.

    I agree with @JeanN00B that the profile stores are not serialized. With this proposal the only shared writes left are explicit (G, p, P, create/edit/rename/delete), so there are few of them, but they still need to re-read before writing (today the panel writes back an in-memory copy of profiles.json), a lock, atomic writes for models.json, and rename retries on Windows (EPERM/EBUSY).

    I agree with @daandradec that p is the right tool for separate repositories and does not cover sessions in the same clone. One detail to add: today, when a pin exists, Enter rewrites the clone-local pin (gentle-ai.ts:4122-4128). In other words, in a pinned repo, one session's Enter changes the profile of every session and worktree of that clone. I believe this is exactly the case I ran into.

    I agree with @LCubero that "use in this session" should go through pi.setModel() / pi.setThinkingLevel() and that persisting Pi's default* settings is a separate concern. Since #1220 the live switch exists (switchLiveOrchestrator), and a2e1f22 / #1522 fixed the live capture for u. What remains is that applying a profile also writes settings.json (gentle-ai.ts:4238), which changes the starting model of every future session. I propose removing that write entirely (see "Orchestrator" below).

    I agree with @AitorDuran, including the last point: a repository default must not rewrite sessions that are already running. In this proposal each session resolves its profile once, at start, so changing p, P or G only affects sessions started afterwards.

    I agree with @Denver2828, with one nuance. A role the profile does not assign should not fall back to whatever global default Pi has at that moment. Inside a profile, "not assigned" should mean "inherit the parent session's live model and thinking". I would make this the default behavior for sessions with a profile, not an opt-in, because a profile is meant to be a complete snapshot (#916): an omitted role inheriting an unrelated global default is exactly the kind of leak this issue is about. Sessions with no profile at all keep today's behavior.

    I agree with #1240 that the review lens path must be covered. Lens captures read models.json directly (gentle-ai.ts:6759, :7587), so today they ignore even the repository pin.

    Consolidated proposal

    1. Panel actions

    Key Writes Affects
    Enter Session only (a session entry, plus the live orchestrator if the profile carries one) This session
    p <git-common-dir>/gentle-ai/profile-pin.json (unchanged) New sessions in this clone
    P <worktree-root>/.pi/gentle-ai/profile.json (unchanged) New sessions in this repo (team)
    G (new) active in profiles.json New sessions everywhere

    Enter never writes pins, models.json, agent frontmatter, subagents.json or settings.json.

    2. Resolving the profile when a session starts

    flowchart TD
        S[session_start] --> C{Is it a<br/>subagent?}
        C -- yes --> X[Do nothing<br/>the parent passed --model]
        C -- no --> E{Session has a<br/>profile entry?}
        E -- yes --> R[Restore the profile<br/>orchestrator: Pi restores it]
        E -- no --> P[Resolve profile<br/>p → P → G]
        P --> N{Session has<br/>messages?}
        N -- yes --> W[Bind profile<br/>keep orchestrator]
        N -- no --> M{Explicit<br/>--model?}
        M -- yes --> W2[Bind profile<br/>keep CLI model]
        M -- no --> O[Bind profile<br/>apply its orchestrator]
    
    Loading

    Three details that matter for the implementation:

    • reason cannot tell a new session from a resumed one. Pi creates the initial runtime without a sessionStartEvent, so pi --resume, --continue and --session all arrive as reason: "startup", the same as a brand new session (Pi 0.87.1, dist/main.js:681 and core/agent-session.js:166). The decision has to come from the session's content.
    • The subagent guard is required. In a regular gentle-pi install, subagent processes load the package, and gentle-ai's session_start has no guard for them today (gentle-ai.ts:9221). Without that guard, every subagent would replace its --model with the profile's orchestrator.
    • An explicit --model wins. Pi applies the CLI model to every runtime it creates, /new included, so the extension should respect it too.

    /fork needs no special handling: Pi copies every entry on the branch (labels excluded) into the forked session, so the profile entry travels with it. /new resolves again from p / P / G, which is the same thing Pi does with the model itself.

    3. Launching a subagent

    flowchart TD
        L[subagent_run<br/>subagent_continue] --> A{Launch-local<br/>route #1025?}
        A -- yes --> RT[Use the route]
        A -- no --> B{Profile assigns<br/>this role?}
        B -- yes --> PR[Use the<br/>profile entry]
        B -- no --> PL[Inherit the parent's<br/>live model and thinking]
        RT & PR & PL --> Q[Resolve and queue<br/>queued and running keep it]
    
    Loading

    This generalizes what the pin already does at launch (withPinnedModelProfiles, gentle-agents.ts:1011): from "the pin" to "the session's profile". Materialized frontmatter and subagents.json stop being read for sessions with a profile, which removes the one-launch lag and any cross-session effect through the materialized stores. Lens captures resolve through the same session profile. When a session delegates into another repository (workspace_root / repository_root), the session's profile still wins over the target repository's defaults.

    4. Orchestrator (and #1478)

    Enter only switches the live orchestrator. New sessions get the profile's orchestrator in step 2, so writing Pi's defaultModel / defaultThinkingLevel is no longer needed, and G does not write settings.json either. Anyone who wants a Pi-wide default still has the "set as default" option in Pi's own /model.

    @danielgap, this overlaps with point 4 of your #1478 design ("apply side unchanged"). The stored contract you describe (explicit value or leave-untouched) fits this proposal as is: leave-untouched simply means step 2 never touches the orchestrator. The only conflict is the settings.json write on apply. Would you be open to leaving the apply side out of #1478 so it can change here, or to aligning both designs before either PR lands?

    5. Compatibility

    • No file migration: active keeps its shape and now means "global default for new sessions".
    • Sessions with no profile at any layer behave exactly as today.
    • The behavior change is Enter, which becomes session-scoped. It should be called out in the release notes and in docs/readme-reference.md.

    6. Suggested slicing

    1. Fix: Enter must not rewrite the clone pin.
    2. Fix: lens captures honor the pin (and later the session profile).
    3. Fix: serialized, atomic profile writes (the @JeanN00B findings), cross-platform.
    4. Feature: session-bound profile (steps 1 to 3 above).
    5. Feature: orchestrator handling (step 4), coordinated with feat(models): explicit orchestrator model/effort selection in /gentle-models so profiles stop silently overwriting the live session #1478.

    The first three are independent fixes and can land before the design discussion is settled.

    Suggested regression coverage
    • Two parent sessions in the same clone selecting different profiles; each launch uses its own.
    • Enter in a pinned repository leaves the pin untouched.
    • Resume (--resume, --continue, --session) restores the bound profile and does not touch the orchestrator.
    • New session: orchestrator applied from p, P or G; not applied with an explicit --model.
    • Subagents never apply an orchestrator.
    • /fork keeps the profile; /new resolves again from the defaults.
    • A role the profile omits inherits the parent's live model and thinking.
    • Editing the bound profile: the session behaves according to the chosen option (name or snapshot + reload); queued and running tasks keep the previous definition.
    • Deleting the bound profile: the session falls back to the next layer.
    • Lens captures use the session profile.
    • Concurrent G / p / create operations do not lose each other's writes, including rename contention on Windows.

    Happy to help with any of these slices once the direction is agreed.

  7. matraket commented on Sep 29, 2026

    @matraket
    Contributor

    @noxsystems @JeanN00B @daandradec @LCubero @AitorDuran @Denver2828

    I've opened a post in the gentle-shell channel on Discord to discuss this topic more directly. I'd appreciate it if you could stop by when you have a moment.

  8. barbatdev commented on Sep 29, 2026

    @barbatdev
    SponsorContributor

    Approved as an umbrella for session-bound profile selection.

    Please keep this as reviewable slices instead of one large PR. I think the first slice should be the smallest end-to-end path:

    • Enter in /gentle:profiles binds the selected profile to the current parent session.
    • The binding is visible as name (session).
    • Future child launches inherit that parent-session binding.
    • Already queued or running children keep the routing resolved when they were queued/launched.
    • Existing unbound sessions continue resolving p → P → global.
    • No mutation of clone pin (p), repository declaration (P), global routing, materialized stores, agent frontmatter, or Pi default settings.

    Follow-up slices can cover explicit reload/edit/delete semantics, orchestrator/default handling, lens/reviewer routing if needed, and concurrent store-write hardening.

    Out of scope for the first PR: global locking/transactions, Windows rename retry hardening, and broader profile-store serialization.

  9. barbatdev commented on Sep 29, 2026

    @barbatdev
    SponsorContributor

    Approved note above still stands. One extra clarification after checking current main: Usage now follows the effective profile to decide which providers to refresh/show.

    That means the session-bound layer should plug into that same effective-profile resolution, not only into subagent launch routing. Otherwise children could launch with a session profile while Usage still reports providers from the local/repo/global profile.

    So for the first slice, please treat the shared precedence as:

    session → local pin (p) → repository declaration (P) → global

    and use that effective source for subagent launch routing, header/status display (name (session)), and Usage provider scope.

  10. danielgap commented on Sep 29, 2026

    @danielgap
    Contributor

    Taking the first slice as scoped above:

    • Enter in /gentle:profiles binds the selected profile to the current parent session, shown as name (session).
    • Child launches inherit the parent-session binding; queued/running children keep their resolved routing.
    • Unbound sessions keep p → P → global; no mutation of pin, declaration, global routing, materialized stores, frontmatter, or Pi defaults.
    • Effective resolution follows session → p → P → global for launch routing, status display, and Usage provider scope per the clarification above.

    I will keep it test-first and post the slice plan here before opening the PR.

  11. danielgap commented on Sep 29, 2026

    @danielgap
    Contributor

    Slice plan for the first PR, mapped to the approved scope:

    Shared state — new lib/session-profile-binding.ts: an in-process map keyed by parent session id holding { name, modelProfiles } (the normalized routing snapshot taken from the saved profile at bind time, defensively copied on read/write). Concurrent Pi processes are isolated by construction; resume/restore and reload semantics stay for follow-up slices.

    1. Enter binds the session (/gentle:profiles): Enter stores the session binding for the selected profile under the current parent session id. It writes nothing: no store active marker, no models.json, no materialized stores, no agent frontmatter, no Pi settings, and no pin or declaration changes, pin present or not. The current global-apply behavior (including its pin-aware repo-scoped re-pin) moves to a new explicit a key ("set as global default"), unchanged in semantics.

    2. Launch routing (gentle-agents): the launch resolver becomes session → p (clone pin) → P (repo declaration) → global. A present session binding replaces modelProfiles wholesale for launches from that parent session, exactly like a winning pin does today. Queued and running children keep the routing resolved when their task request was created.

    3. Display: the shell bar and the profiles panel show the effective profile as name (session) when a binding is present, ahead of pin (source) and the global active name.

    4. Usage provider scope: usage refresh covers the providers named by the session binding's routing (distinct provider/ prefixes of its model ids) alongside the live provider, so the panel meters what the session actually launches with.

    Tests, written first: binding store (isolation per session, snapshot immutability); launch precedence session > pin > global and queued-request retention; reader precedence and the (session) label; panel Enter = session bind with zero file writes (spied), a = legacy global apply; existing unbound behavior untouched.

    Out of scope per the approval note: reload/edit/delete binding, orchestrator/default handling, lens/reviewer routing, persistence across resume, store-write hardening.

  12. noxsystems commented on Sep 29, 2026

    @noxsystems
    ContributorAuthor

    Thanks for taking the first slice, @danielgap. I won't open an overlapping PR. I can review and test it when it's ready, especially two parent sessions in the same clone, zero shared or pin writes on Enter, queued-task stability, and agreement between child routing, status, and Usage on the effective profile.

    I have a local prototype with persisted session snapshots and resume/fork tests. Its UI keys and per-field fallback differ from the approved first slice, so I would adapt the relevant pieces rather than cherry-pick it. After the first slice lands, would a separate, narrowly scoped persistence/resume follow-up be useful? Happy to coordinate its contract before starting.

  13. danielgap commented on Sep 29, 2026

    @danielgap
    Contributor

    Thanks @noxsystems, the chain is ready for you:

    On your four scenarios, so you know what is already pinned by tests versus what would benefit most from your live testing:

    • Zero shared or pin writes on Enter: asserted in feat(profiles): bind the active profile to the parent session (#1064 1/2) #1557's tests (store, Pi settings, models.json, materialized subagents.json, and both pin layers stay byte-identical, including with a winning pin present).
    • Queued-task stability: the binding is resolved at task-request creation, so a queued child keeps the routing frozen into its request; the precedence itself is unit-tested, but a live queue check is welcome.
    • Two parent sessions in the same clone: this one is manual by nature (two live processes), and it is the scenario unit tests cannot cover. Two windows, bind different profiles in each, launch children from both, and watch that neither session's status, launches, or usage drift.
    • Agreement between child routing, status, and Usage: each consumer is tested through the same store, but cross-surface agreement in a live session is exactly the end-to-end check worth doing.

    On the persistence/resume follow-up: yes, that would be useful and it is the natural next slice. The store is deliberately in-process for slice 1 (lib/session-profile-binding.ts), and everything reads it through one seam, so persisted snapshots could plug into the same read path without touching the three consumers again. Coordinating the contract first is the right call, and it should probably line up with barbatdev's follow-up list (reload/edit/delete semantics in particular, since persistence and reload rules shape each other). Happy to sync on the contract whenever you start.

  14. danielgap commented on Sep 29, 2026

    @danielgap
    Contributor

    Recording two test-debt items from the native review of slice 2 (#1558, lineage review-0cb9827ae718d863, both informational advisories) so they stay visible for the follow-up slices:

    1. Routing-freeze for queued children — no dedicated test proves that a child queued under one session binding keeps its frozen routing after the session rebinds (the launch seam resolves routing once at task-request creation; only the pure precedence helper is tested today).
    2. Session-over-pin precedence at launch — no test with both a winning pin and a session binding present, proving the session wins at the actual launch and reader seams (each layer is tested alone).

    Plan: cover both in the next slice that touches this area, or a small dedicated test: PR under this umbrella if it lands first.

  15. AlejandroTatum commented on Sep 30, 2026

    @AlejandroTatum

    Adding a real-world data point for this request.

    I work on several repositories in parallel, each in its own Pi session, and each wants a different routing profile: one on a Claude-only profile, another on a GPT/GLM profile, everything else on the global default. Today that takes three separate mechanisms, each covering only part of it:

    When any of the three drifts, the session quietly runs on the global profile. The only way I found to notice was reading the subagent session JSONL files. It happened often enough that I stopped trusting what I thought each session was running.

    What would remove the friction: the profile chosen when a session starts stays bound to that session — for the orchestrator and every subagent it launches — regardless of what another session activates later. Happy to test the session-binding work (#1557/#1558) against this setup.

  16. 86 remaining items

  17. matraket commented on Oct 23, 2026

    @matraket
    Contributor

    @barbatdev starting the 3c read-side slice. One finding changes how the /gentle:models part can stay read-only, so flagging it before I code it.

    /gentle:profiles is straightforward: its effective-routing table goes through resolveSessionProfile, so it shows the Enter binding, the frozen profile and the pin.

    /gentle:models is an editor, not just a view: its rows are the draft that Ctrl+S writes to the global routing. If the rows were seeded from the session's profile, saving would silently copy that whole profile into the global routing, for example after changing a single thinking level. That is a write-side change by another route, which is what you asked to keep out.

    So unless you prefer otherwise, I'll keep the rows as what the panel edits (the global routing) and make the session visible:

    • A header naming the profile this session launches with and its layer, for example balanced-gpt (session).
    • A mark on each row whose launch model differs, for example launches: openai/gpt-….

    The tests pin both reported cases through the public render: with Enter and with a pin, the panel shows what launches use.

    The header and the /gentle:profiles fix stay as they are once D2 lands. The per-row marks are a bridge until then: once /gentle:models edits the session's profile they always match, and they go away.

    I'll sync with @noxsystems on the 3b-i overlap in Discord.

  18. barbatdev commented on Oct 23, 2026

    @barbatdev
    SponsorContributor

    Good catch, and yes, I prefer your reading. Seeding the editor rows from the session profile would turn the next Ctrl+S into a silent copy of that profile into the global routing, and that is exactly the write-side change I wanted to keep out of this slice. The header with the session's launch profile and layer plus the per-row launches marks give users the visibility the reports are actually asking for, without touching what the panel edits. Go ahead with that plan.

    One adjustment on issue closure: this slice closes #2451 but should not auto-close #2276. Efirvida's report explicitly asks /gentle:models to display and edit the session profile's agent models, and the edit half is D2. Reference #2276 as resolved on the display side with D2 still open, so the expectation is set correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requeststatus:approvedIssue approved by maintainer; PR may be openedtype:featureNew feature

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions