meanwhile

module
v0.0.0-...-05e9f27 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 7, 2026 License: Apache-2.0

README

Meanwhile

CI Go Reference Go Report Card License

Meanwhile is a collaboration runtime for AI agents. It's not a task pipeline—it's a workplace. Instead of asking "which agent runs next?", it asks "what kind of collaboration is happening right now?".

The core is intentionally minimal. Collaboration modes live in protocols that can evolve independently of the engine, with hook points for dynamic control.

Why Meanwhile

Most agent frameworks model execution flow. Meanwhile models human collaboration: brainstorming, debate, handoffs, consensus-building, and facilitation. It's built for open-ended reasoning—research, strategy, design critique, and sense-making—not rigid workflows.

Meanwhile... agents collaborate naturally, logs read like workplace memos, and protocols feel like office dynamics.

Features

  • Ergonomic builder APIs - Agent creation, session setup, and protocol configuration with fluent interfaces
  • Model-first design - Agents specify models; the engine handles provider resolution automatically
  • Collaboration protocols - Brainstorming, adversarial debate, consensus, breakouts, handoffs, and more
  • Typed tool construction - Build tools from Go structs with automatic schema generation
  • Toolkits + guardrails - Assign bundles of tools with allow/deny policies
  • Structured results - RunResult with transcript, final message, events, and metadata
  • Durable tool calls - Long-running tool execution can pause and resume safely
  • Clean logging - Workplace-themed Worklog formatter turns events into readable narratives
  • Protocol-as-tool - Convert any protocol into a callable tool for nested collaboration
  • Streaming events - Real-time event bus for observability and dynamic control
  • Multi-provider - OpenAI (with more coming)
  • Memory - Built-in registries for context and event storage
  • Human escalation - ask_human tool, human participants, and integration routing
  • Inbound responses - Webhook and Slack command handlers for human replies
  • Timeout handling - Default timeout policy + pluggable scheduler drivers
  • Request registry - Map request IDs to sessions (in-memory or Redis)
  • Telemetry - Integration hooks (Langfuse adapter included)

Quickstart

Single Agent (The Simple Path)
package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/runmeanwhile/meanwhile/pkg/engine"
    "github.com/runmeanwhile/meanwhile/pkg/logger"
    "github.com/runmeanwhile/meanwhile/pkg/message"
    "github.com/runmeanwhile/meanwhile/pkg/provider/openai"
)

func main() {
    ctx := context.Background()

    // Setup provider and engine with clean logging
    provider, _ := openai.FromEnv()
    eng, _ := engine.New(
        engine.WithProvider(provider),
        engine.WithLogger(logger.Worklog(os.Stdout)),
    )

    // Create agent with builder API
    dale := eng.Agent("Dale from IT").
        Prompt("You are Dale, an IT support tech in 2001. Keep it brief.").
        Model("gpt-4o-mini").
        Build()

    // Run agent with simple shortcut
    result, err := dale.Run(message.User("My printer says PC LOAD LETTER. Help!"))
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("\n=== Dale's Response ===")
    fmt.Println(result.Content)
}

Output:

09:23:41 [Dale from IT] thinking...
09:23:42 [Dale from IT] It means the printer is out of paper...

=== Dale's Response ===
It means the printer is out of paper in the letter-size tray. Load paper and hit continue.
Multi-Agent Collaboration
// Create multiple agents
manager := eng.Agent("Manager").
    Prompt("You are a project manager. Delegate when needed.").
    Model("gpt-4o-mini").
    Build()

engineer := eng.Agent("Engineer").
    Prompt("You are a senior engineer. Provide technical solutions.").
    Model("gpt-4o-mini").
    Build()

// Use session builder for protocols
sess, _ := eng.Session("ISO Audit").
    Participant(manager).
    Participant(engineer).
    Protocol(protocol.Handoff(manager, engineer)).
    Tags("audit", "compliance").
    Start(ctx)

// Run and get structured result
result, _ := eng.Run(ctx, sess.ID(), agent.User("Audit the payroll system"))

fmt.Println("Final:", result.Final)
fmt.Println("Transcript:", len(result.Transcript), "messages")
Session Persistence

Sessions can be rehydrated across processes by providing a SessionStore:

store := engine.NewInMemorySessionStore() // or your own implementation
eng, _ := engine.New(engine.WithSessionStore(store))

// Create session in one process
sess, _ := eng.NewSession(ctx, engine.SessionConfig{
    ID:           "ticket-123",
    Protocol:     protocol.Solo(),
    Participants: []protocol.Participant{manager},
})

// Later (another engine instance), the session can be rehydrated
_, _ = eng.Run(ctx, "ticket-123", agent.User("hello"))

Stores can also implement engine.SessionStateStore to persist pending human input requests and pending tool executions for pause/resume introspection. Pending requests are restored for visibility and routing; resuming them requires the original in-process protocol callbacks.

Human Escalation & Timeouts

Meanwhile supports human-in-the-loop escalation via the ask_human tool, with outbound integrations and inbound response handlers:

moderator := eng.Agent("Moderator").
    Prompt("Call ask_human when you need input.").
    Build()

human := eng.Human("User").
    ContactVia("slack", channelID).
    PreferredChannel("slack").
    Build()

sess, _ := eng.Session("Escalation").
    Participant(moderator).
    Participant(human).
    Protocol(protocol.Solo()).
    TimeoutPolicy(engine.ContinueWithNote("No response received; continuing.")).
    Build(ctx)

_, _ = sess.EnableAskHumanTool()

For scheduled timeout handling across processes, provide a timeout scheduler (in-memory or Redis driver) and a request registry (in-memory or Redis) for inbound responders.

Meanwhile also records human request lifecycle state (pending/sent/failed/answered/timed_out) in a HumanRequestStore so you can build inbox-style UIs or dashboards:

requests, _ := eng.ListHumanRequests(ctx, engine.HumanRequestFilter{
    Statuses: []engine.HumanRequestStatus{engine.HumanRequestStatusPending},
    Limit:    50,
})

handler := &server.HumanRequestInboxHandler{Engine: eng}
http.Handle("/inbox/human-requests", handler)
Context Management

Control prompt size and tool output growth per run:

_, _ = sess.RunAgent(ctx, manager, protocol.RunRequest{
    Messages: []agent.Message{message.User("Summarize the latest status.")},
    Context: protocol.ContextConfig{
        MaxPromptTokens:    4000,
        RollingWindow:      12,
        MaxToolOutputChars: 1500,
        Summarization: protocol.SummarizationConfig{
            Enabled:         true,
            ThresholdTokens: 6000,
        },
    },
})

If the provider implements provider.TokenEstimator, the engine uses it for token budgets; otherwise it falls back to the built-in heuristic (4 chars ≈ 1 token).

Durable Execution Defaults

Configure retries, auto-summarization, and run timeouts globally:

cfg := config.Config{
    Global: config.GlobalConfig{
        RunTimeoutSeconds: 600,
        ProviderRetry: config.ProviderRetryConfig{
            MaxRetries:      5,
            InitialInterval: 1 * time.Second,
            MaxInterval:     10 * time.Second,
            Multiplier:      2,
        },
        Context: config.ContextConfig{
            AutoSummarize: config.AutoSummarizeConfig{
                SummarizeAtTokens: 4000,
                MinKeepMessages:   6,
            },
        },
    },
}

eng, _ := engine.New(
    engine.WithConfig(cfg),
    engine.WithContextSummarizer(mySummarizer),
)
Typed Tools
// Define tool arguments as a struct
type DelegateArgs struct {
    Task   string `json:"task" description:"Task to hand off"`
    Reason string `json:"reason" description:"Why specialist is needed"`
}

// Create typed tool - schema generated automatically
delegateTool := tool.New("delegate", func(ctx context.Context, args DelegateArgs) (string, error) {
    // args is already unmarshaled and validated
    specialist := eng.Agent("Specialist").Model("gpt-4o-mini").Build()
    result, _ := specialist.Run(agent.User(args.Task))
    return result.Final, nil
})

eng.ToolRegistry().Register(delegateTool)
Toolkits + Tool Policy

Toolkits bundle related tools (filesystem, system, MCP, internal APIs) and can be attached to a session with a policy guardrail:

// Register toolkits once on the engine.
fsToolkit, _ := filesystem.New("filesystem", filesystem.Config{
    Roots: []string{"/repo"},
})
_ = eng.RegisterToolkit(fsToolkit)
_ = eng.RegisterToolkit(system.New("system", system.Config{
    Allow: []string{"rg", "go", "git"},
}))

sess, _ := eng.Session("Ops").
    Participant(manager).
    Protocol(protocol.Solo()).
    Toolkits("filesystem", "system").
    ToolPolicy(tool.Policy{
        Mode:       tool.PolicyAllowlist,
        AllowTags:  []string{"filesystem", "read", "write", "system", "path"},
        EnforcedBy: "ops",
        Reason:     "limit to repo operations",
    }).
    Build(ctx)

_ = sess
Durable Tool Calls

Tools can pause a run while waiting on external work (jobs, long-running tasks, human approval) and resume later:

deploy := tool.New("deploy", func(ctx context.Context, call tool.Call) (tool.Result, error) {
    // enqueue job, return awaiting request
    return tool.Await(call, tool.WithContext("waiting for deploy job"))
})

// Later, resume the pending tool request (requestID from RunResult.AwaitingTool or PendingToolRequests)
result := tool.Result{ToolID: "deploy", Output: "deploy complete"}
_, _ = sess.ResumeTool(ctx, requestID, result)
MCP Tools
ctx := context.Background()

// Connect to an MCP server (stdio)
github, _ := eng.MCP("github").
    Command("github-mcp").
    Env("GITHUB_TOKEN", os.Getenv("GITHUB_TOKEN")).
    Register(ctx)

// Use MCP tools by ID (prefix defaults to server name)
agent := eng.Agent("Ops").
    Prompt("Use the GitHub tools when needed.").
    Model("gpt-4o-mini").
    Tools("github.search_repos", "github.create_issue").
    Build()

_ = github
_ = agent
Protocol as Tool
// Convert any protocol into a callable tool
handoffTool := eng.AsTool(
    protocol.Handoff(manager, specialist),
    engine.WithToolName("escalate"),
    engine.WithToolDescription("Escalate complex issues to specialist"),
)

eng.ToolRegistry().Register(handoffTool)

// Now agents can call it naturally
coordinator := eng.Agent("Coordinator").
    Prompt("You coordinate work. Use tools when needed.").
    Model("gpt-4o-mini").
    Tools("escalate").
    Build()

Built-in Protocols

Meanwhile ships with collaboration protocols that mirror workplace dynamics:

  • Solo - Single-agent execution (default for Agent.Run())
  • Handoff - Simple delegation from one agent to another
  • Brainstorming - Diverge, interact, and vote like a real brainstorm
  • Adversarial - Debate with opposing positions and optional synthesis
  • Consensus - Convergent collaboration to reach shared outcomes
  • Breakout - Parallel group work with synthesis
  • Caucus - Private per-participant prep before reconvening

All protocols support functional options:

proto := protocol.Brainstorming(
    protocol.WithBrainstormingConcurrency(3),
    protocol.WithBrainstormingInteractionRounds(2),
    protocol.WithBrainstormingVotesPerAgent(3),
)

proto := consensus.Consensus(
    consensus.WithAgenda(agenda.WithScope("Policy-level decision")),
    consensus.WithChair(chair.WithInterventions(0.4, 0.7, 0.9)),
    consensus.WithPulseCheck(pulse.WithMaxConditions(3)),
)

Examples

See examples/ for complete working demos with 1999-2001 office scenarios. Highlights include:

  • 01-single-agent — "PC LOAD LETTER" troubleshooting
  • 05-protocol-brainstorming — Divergent ideation
  • 06-protocol-consensus — Consensus building
  • 19-human-turn-based — Human participants in protocols
  • 21-ask-human-tool — Agent-driven escalation
  • 22-slack-integration — Outbound Slack delivery
  • 23-webhook-receiver — Inbound webhook responses
  • 24-timeout-handling — Scheduled timeout handling

For the full list, see examples/README.md and examples/OVERVIEW.md.

Design Principles

  • Protocol-first - Collaboration modes as first-class abstractions
  • Event-driven - Streaming events for observability and control
  • Ergonomic by default - Builder APIs, smart defaults, clean logs
  • Workplace metaphors - Sessions, participants, facilitators, handoffs
  • Type-safe where it matters - Object references over string IDs

Documentation

Go Version

This repository targets Go 1.24+. Ensure Go 1.24 is in your PATH if multiple versions are installed.

License

Meanwhile is licensed under the Apache License 2.0. See LICENSE.

Meanwhile is a trademark of its owner. See TRADEMARK.md for usage guidance.

Future: CLI and Studio

The roadmap includes a CLI for session management and a web-based Studio for visual collaboration. See ROADMAP.md for details on planned features.


Meanwhile... agents collaborate, protocols orchestrate, and logs tell the story. ✨

Directories

Path Synopsis
cmd
protocol-eval command
examples
01-single-agent command
06-protocol-consensus command
Package main demonstrates the consensus protocol with multiple agents reaching agreement through structured round-robin discussion.
Package main demonstrates the consensus protocol with multiple agents reaching agreement through structured round-robin discussion.
10-memory-store command
13-full-stack command
14-semantic-memory command
Example 14: Semantic Memory - Intelligent Context Retrieval
Example 14: Semantic Memory - Intelligent Context Retrieval
19-human-turn-based command
Package main demonstrates turn-based human participation in a protocol.
Package main demonstrates turn-based human participation in a protocol.
21-ask-human-tool command
Package main demonstrates the ask_human tool for human escalation.
Package main demonstrates the ask_human tool for human escalation.
22-slack-integration command
Package main demonstrates outbound Slack integration for ask_human.
Package main demonstrates outbound Slack integration for ask_human.
23-webhook-receiver command
Package main runs a webhook server for human responses.
Package main runs a webhook server for human responses.
24-timeout-handling command
Package main demonstrates scheduled timeout handling for human requests.
Package main demonstrates scheduled timeout handling for human requests.
pkg
agent
Package agent defines agent identities, messages, and configuration.
Package agent defines agent identities, messages, and configuration.
collab/agenda
Package agenda provides scope refinement for collaboration protocols.
Package agenda provides scope refinement for collaboration protocols.
collab/caucus
Package caucus runs private, per-participant collaboration rounds.
Package caucus runs private, per-participant collaboration rounds.
collab/chair
Package chair provides facilitation interventions and closing summaries for protocols.
Package chair provides facilitation interventions and closing summaries for protocols.
collab/interrupts
Package interrupts defines a collaboration-kit wrapper for hook-driven interjections.
Package interrupts defines a collaboration-kit wrapper for hook-driven interjections.
collab/minutes
Package minutes aggregates structured results from collaboration protocols.
Package minutes aggregates structured results from collaboration protocols.
collab/planning
Package planning provides primitives for creating structured implementation plans.
Package planning provides primitives for creating structured implementation plans.
collab/pulse
Package pulse provides position signaling and voting tools for collaboration protocols.
Package pulse provides position signaling and voting tools for collaboration protocols.
collab/roundtable
Package roundtable provides turn ordering and context packaging helpers for protocols.
Package roundtable provides turn ordering and context packaging helpers for protocols.
config
Package config defines global configuration structures and loaders.
Package config defines global configuration structures and loaders.
engine
Package engine provides the core session runtime for Meanwhile.
Package engine provides the core session runtime for Meanwhile.
event
Package event defines the shared event model used across Meanwhile.
Package event defines the shared event model used across Meanwhile.
hook
Package hook defines hook interfaces for intercepting core loop actions.
Package hook defines hook interfaces for intercepting core loop actions.
integration
Package integration delivers human requests to external channels.
Package integration delivers human requests to external channels.
logger
Package logger provides event logging with workplace-themed formatting.
Package logger provides event logging with workplace-themed formatting.
mcp
memory
Package memory provides memory store interfaces and implementations.
Package memory provides memory store interfaces and implementations.
message
Package message provides message constructors and types for agent communication.
Package message provides message constructors and types for agent communication.
protocol
Package protocol defines collaboration protocol interfaces and registry.
Package protocol defines collaboration protocol interfaces and registry.
protocol/consensus
Package consensus implements a structured multi-agent consensus protocol.
Package consensus implements a structured multi-agent consensus protocol.
provider
Package provider defines LLM provider interfaces and registries.
Package provider defines LLM provider interfaces and registries.
provider/openai
Package openai provides the OpenAI Responses API provider.
Package openai provides the OpenAI Responses API provider.
requestregistry
Package requestregistry provides request registry implementations.
Package requestregistry provides request registry implementations.
scheduler
Package scheduler provides pluggable job scheduling drivers.
Package scheduler provides pluggable job scheduling drivers.
server
Package server provides HTTP handlers for inbound integrations.
Package server provides HTTP handlers for inbound integrations.
telemetry
Package telemetry defines tracing abstractions for Meanwhile.
Package telemetry defines tracing abstractions for Meanwhile.
telemetry/langfuse
Package langfuse provides a Langfuse telemetry client via OpenTelemetry.
Package langfuse provides a Langfuse telemetry client via OpenTelemetry.
tool
Package tool provides typed tools for agent actions.
Package tool provides typed tools for agent actions.
toolkit
Package toolkit groups related tools into reusable bundles.
Package toolkit groups related tools into reusable bundles.
toolkit/agentcall
Package agentcall provides tools for delegating to configured agents.
Package agentcall provides tools for delegating to configured agents.
toolkit/filesystem
Package filesystem provides guarded filesystem tools.
Package filesystem provides guarded filesystem tools.
toolkit/system
Package system provides guarded system information tools.
Package system provides guarded system information tools.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL