Skip to content

feat: api.slothlet.restart() — a clean-slate rebuild that swaps in a fresh instance behind the same api reference #504

Closed

Description

@Shinrai

Problem

reload() is deliberately not a clean slate. After a full reload, slothlet keeps:

  1. References — api and any held leaf (api.math.add) keep working.
  2. Runtime mutations — every api.slothlet.api.add() / remove() is replayed from the operation history (docs/RELOAD.md, "Operation History and Replay").
  3. Runtime assignments — self.x = … overrides are flagged userAssigned and survive verbatim (O15, docs/API-RULES/API-COLLISION-CONDITIONS.md).

That is the right contract for hot-reloading code while an app keeps running, but there is no way to get the opposite: "throw away everything that happened at runtime and come back up exactly as a fresh slothlet({...}) would". Example:

// api/conn.mjs — the module's top level creates the emitter
import { EventEmitter } from "node:events";
const conn = new EventEmitter();
export default conn;
api.conn.handlers = { onSend }; // runtime assignment → userAssigned (O15)
await api.slothlet.api.reload(); // conn.mjs re-runs, but api.conn.handlers is still there

After a reload, api.conn is a new emitter from the module's top level, yet the runtime-assigned handlers is re-applied on top of it. For a "start over" there is currently nothing short of shutting the instance down and building a new one, which invalidates every reference callers hold.

Proposal

Keep reload() exactly as it is. Add api.slothlet.restart():

  • Builds a new internal instance from the instance's original config (same as the slothlet({...}) call that created it).
  • Swaps it in behind the existing api root proxy, so callers' references keep working, the same way reload preserves them.
  • Shuts the old instance down through the normal teardown path (shutdown lifecycle, handler cleanup, permission/version manager shutdown()), so nothing from it leaks.
  • Nothing runtime is carried over: no userAssigned overrides, no module-scope state from the old imports (fresh import, cache-busted as reload already does).

Open questions (decide before implementing)

  1. Runtime add() / remove() history: replay it (restart = "fresh process with the same mounts") or drop it (restart = "exactly the original slothlet({...}) call")?
  2. Runtime-registered hooks, permission rules and event subscriptions: carried over or dropped? Dropping matches "clean slate", but a caller that registered a hook at startup loses it.
  3. Held child references: a caller holding api.conn (not just api) — should it re-point to the new instance's conn, as reload does, or is only the root reference guaranteed?
  4. Lifecycle events: a new restart event, or shutdown (old) + init (new)?

Activity

  1. added
    priority: mediumShould be addressed in the normal course of development
    type: feature requestA request to add new functionality that does not currently exist
    area: coreTouches core library / runtime source code
    status: not startedNot implemented yet — no code exists for this
    on Sep 28, 2026
  2. Shinrai commented on Sep 29, 2026

    @Shinrai
    ContributorAuthor

    Design decisions (maintainer, 2026-09-29): a restart is exactly like creating the instance from scratch; reload keeps holding onto things.

    1. Runtime add() / remove() history: dropped — restart = the original slothlet({...}) call.
    2. Runtime-registered hooks, permission rules, event subscriptions: dropped (clean slate).
    3. Held child references (const conn = api.conn): re-point to the new instance's value at the same path, as after reload; a path that no longer exists throws a clear error on use.
    4. Lifecycle events, in order: restart (before anything is torn down) → shutdown (old instance, normal teardown) → init (new instance) → restarted (swap complete).
  3. added
    status: in progressPartially implemented — actively being built
    and removed
    status: not startedNot implemented yet — no code exists for this
    on Sep 29, 2026
  4. added 2 commits that reference this issue on Oct 2, 2026
    ba7bd7b
    0e11353
  5. cldmv-bot commented on Oct 2, 2026

    @cldmv-bot
    Contributor

    Marked status: implemented — resolved by #545, merged into next. This issue closes automatically when that work ships to the default branch.

  6. added
    priority: highNeeds attention soon — not blocking, but don't let it sit
    and removed
    priority: mediumShould be addressed in the normal course of development
    on Oct 2, 2026
  7. cldmv-bot commented on Oct 3, 2026

    @cldmv-bot
    Contributor

    Closed in v3.22.0 — resolved by #545.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: coreTouches core library / runtime source codepriority: highNeeds attention soon — not blocking, but don't let it sitstatus: implementedBuilt and deployed, but not yet fully tested/verifiedtype: feature requestA request to add new functionality that does not currently exist

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions