Nous.Teams.SharedState (nous v0.15.6)

View Source

ETS-based shared state for per-team discoveries and file region claims.

Owns an ETS table that stores:

  • Discoveries — findings shared by agents (topic, content, timestamp)
  • Region claims — file region locks to prevent editing conflicts

Architecture

Each team gets its own SharedState GenServer. The ETS table is owned by this process and destroyed when the process terminates. Claims auto-expire after a configurable timeout (default 5 minutes).

Quick Start

{:ok, pid} = SharedState.start_link(team_id: "team_1")

SharedState.share_discovery(pid, "alice", %{topic: "Bug in parser", content: "Found null check missing"})
SharedState.get_discoveries(pid)

:ok = SharedState.claim_region(pid, "alice", "lib/parser.ex", 10, 20)
{:error, :conflict} = SharedState.claim_region(pid, "bob", "lib/parser.ex", 15, 25)
:ok = SharedState.release_region(pid, "alice", "lib/parser.ex")

Summary

Functions

Returns a specification to start this module under a supervisor.

Claim a file region for exclusive editing.

Get all current region claims.

Retrieve all discoveries stored for this team.

Release all region claims for an agent on a specific file.

Store a discovery from an agent.

Start a SharedState process for a team.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

claim_region(pid, agent_name, file_path, start_line, end_line)

@spec claim_region(
  pid(),
  String.t(),
  String.t(),
  non_neg_integer(),
  non_neg_integer()
) ::
  :ok | {:error, :conflict}

Claim a file region for exclusive editing.

Returns :ok if the claim succeeds, or {:error, :conflict} if the region overlaps with an existing claim by a different agent.

Examples

:ok = SharedState.claim_region(pid, "alice", "lib/parser.ex", 10, 20)
{:error, :conflict} = SharedState.claim_region(pid, "bob", "lib/parser.ex", 15, 25)

get_claims(pid)

@spec get_claims(pid()) :: [map()]

Get all current region claims.

Returns a list of maps with :agent, :file, :start_line, :end_line, and :expires_at keys.

Examples

claims = SharedState.get_claims(pid)
# [%{agent: "alice", file: "lib/parser.ex", start_line: 10, end_line: 20, expires_at: ~U[...]}]

get_discoveries(pid)

@spec get_discoveries(pid()) :: [map()]

Retrieve all discoveries stored for this team.

Returns a list of maps with :agent, :topic, :content, and :timestamp keys.

Examples

discoveries = SharedState.get_discoveries(pid)
# [%{agent: "alice", topic: "Bug", content: "...", timestamp: ~U[...]}]

release_region(pid, agent_name, file_path)

@spec release_region(pid(), String.t(), String.t()) :: :ok

Release all region claims for an agent on a specific file.

Examples

:ok = SharedState.release_region(pid, "alice", "lib/parser.ex")

share_discovery(pid, agent_name, discovery_map)

@spec share_discovery(pid(), String.t(), map()) :: :ok

Store a discovery from an agent.

The discovery map should contain :topic and :content keys. A timestamp is automatically added.

Examples

SharedState.share_discovery(pid, "alice", %{topic: "Bug", content: "Null check missing"})

start_link(opts)

@spec start_link(keyword()) :: GenServer.on_start()

Start a SharedState process for a team.

Options

  • :team_id (required) — unique identifier for the team
  • :claim_ttl — claim expiration in ms (default: 5 minutes)
  • :name — optional GenServer name