
Agent Signal
- 10 installs
- 81.3k repo stars
- Updated August 5, 2026
- lobehub/lobe-chat
Helps with ai & agent building tasks during AI-assisted development.
About
agent-signal is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- agent-signal
- AI & Agent Building
- AI-coding skill
Agent Signal by the numbers
- 10 all-time installs (skills.sh)
- +1 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #11,959 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/lobehub/lobe-chat --skill agent-signalAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 10 |
|---|---|
| repo stars | ★ 81.3k |
| Last updated | August 5, 2026 |
| Repository | lobehub/lobe-chat ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Agent Signal
Use this skill to implement event-driven background work for agents without coupling the work to the foreground chat request.
Agent Signal has one consistent shape:
source event -> signal interpretation -> action execution -> built-in result signals
Start Here
1. Read references/architecture.md to map the package boundary, runtime queue, scope model, and async workflow handoff. 2. Read references/handlers.md before writing any new policy, source handler, signal handler, or action handler. 3. Read references/observability.md when you need tracing, metrics, debugging, or workflow snapshot visibility.
Use The Right Entry Point
- Use
emitAgentSignalSourceEvent(...)when a server-owned producer should execute the pipeline immediately. - Use
executeAgentSignalSourceEvent(...)when a worker or controlled backend path already owns execution timing and may inject a runtime guard backend. - Use
enqueueAgentSignalSourceEvent(...)when the caller should return quickly and let Upstash Workflow process the event out-of-band. - Use
emitAgentSignalSourceEventWithStore(...)for isolated tests or evals that should avoid ambient Redis state.
Read:
apps/server/src/services/agentSignal/index.tsapps/server/src/workflows/agentSignal/index.tsapps/server/src/workflows/agentSignal/run.ts
Core Model
source: A normalized fact that happened. Sources come from producers such as runtime lifecycle events, user messages, or bot ingress.signal: A semantic interpretation derived from one source or from another signal. Signals express meaning, routing, or policy state.action: A concrete side effect planned from one signal. Actions do the work.policy: An installable middleware bundle that registers source, signal, and action handlers.procedure: Not a distinct runtime node. Treat "procedure" as the end-to-end flow for one use case: ingress source, matching handlers, planned actions, execution result, and observability.
Keep the boundaries strict:
- Add a new
sourcewhen the outside world produced a new event. - Add a new
signalwhen the system needs a reusable semantic interpretation. - Add a new
actionwhen the runtime needs a concrete side effect. - Add or update a
policywhen you are wiring those pieces together.
Implementation Workflow
1. Decide whether the use case is synchronous or quiet background work. 2. Define or reuse a source type in apps/server/src/services/agentSignal/sourceTypes.ts. 3. Define or reuse signal and action types in apps/server/src/services/agentSignal/policies/types.ts. 4. Implement handlers with defineSourceHandler, defineSignalHandler, or defineActionHandler. 5. Bundle handlers with defineAgentSignalHandlers(...). 6. Register the policy in apps/server/src/services/agentSignal/policies/index.ts and pass it into the runtime factory if needed. 7. Add or update ingress code that emits or enqueues the source event. 8. Add observability and tests before considering the flow complete.
Default Reading Set
- Shared semantic core:
packages/agent-signal/src/index.ts packages/agent-signal/src/base/builders.ts packages/agent-signal/src/base/types.ts
- Server-owned runtime and middleware:
apps/server/src/services/agentSignal/runtime/AgentSignalRuntime.ts apps/server/src/services/agentSignal/runtime/AgentSignalScheduler.ts apps/server/src/services/agentSignal/runtime/middleware.ts apps/server/src/services/agentSignal/runtime/context.ts
- Existing policy example:
apps/server/src/services/agentSignal/policies/analyzeIntent/index.ts apps/server/src/services/agentSignal/policies/analyzeIntent/feedbackSatisfaction.ts apps/server/src/services/agentSignal/policies/analyzeIntent/feedbackDomain.ts apps/server/src/services/agentSignal/policies/analyzeIntent/feedbackAction.ts apps/server/src/services/agentSignal/policies/analyzeIntent/actions/userMemory.ts
- Observability:
apps/server/src/services/agentSignal/observability/projector.ts apps/server/src/services/agentSignal/observability/traceEvents.ts packages/observability-otel/src/modules/agent-signal/index.ts
Implementation Rules
- Reuse existing source, signal, and action types before adding new ones.
- Keep source handlers focused on interpretation and fan-out, not heavy side effects.
- Keep action handlers responsible for side effects, idempotency, and executor-style result reporting.
- Use stable ids and idempotency keys when the same source can arrive more than once.
- Preserve scope discipline. The runtime uses
scopeKeyto serialize related background work. - Prefer the dedicated shared package types and builders from
@lobechat/agent-signalfor normalized nodes and result contracts. - Add focused tests near the touched runtime, policy, or store module. Existing tests under
apps/server/src/services/agentSignal/**/__tests__are the reference pattern.
References
- Architecture and boundaries:
references/architecture.md - Writing handlers and policies:
references/handlers.md - Observability, metrics, and debugging:
references/observability.md
interface:
display_name: 'Agent Signal'
short_description: 'Build AgentSignal sources, signals, actions, and policies.'
default_prompt: 'Use $agent-signal to add a new Agent Signal source, policy, handler, or observability flow.'
Agent Signal Architecture
Pipeline
Use this mental model first:
producer
-> emitAgentSignalSourceEvent(...) or enqueueAgentSignalSourceEvent(...)
-> emitSourceEvent(...)
-> dedupe + scope lock + source normalization
-> runtime.emitNormalized(source)
-> source handlers
-> signal handlers
-> action handlers
-> built-in result signals
-> observability projection + persistenceThe scheduler is queue-driven, not hard-coded for one policy:
source node
-> matching source handlers
-> dispatch signals/actions
-> matching signal handlers
-> dispatch more signals/actions
-> matching action handlers
-> ExecutorResult
-> signal.action.applied | signal.action.skipped | signal.action.failedRead:
apps/server/src/services/agentSignal/index.tsapps/server/src/services/agentSignal/sources/index.tsapps/server/src/services/agentSignal/runtime/AgentSignalScheduler.ts
Package Boundaries
packages/agent-signal
Treat this as the shared semantic core.
It provides:
- base node types: source, signal, action
- builders:
createSource,createSignal,createAction - built-in result signal types
- runtime result contracts such as
RuntimeProcessorResultandExecutorResult
Read:
packages/agent-signal/src/base/types.tspackages/agent-signal/src/base/builders.tspackages/agent-signal/src/types/events.tspackages/agent-signal/src/types/builtin.ts
apps/server/src/services/agentSignal
Treat this as the server-owned implementation layer.
It owns:
- source catalogs and payload maps
- policy-specific signal and action catalogs
- middleware registration
- runtime scheduling and guard backends
- Redis-backed dedupe, waypoint, and policy state
- service entrypoints for synchronous and async execution
packages/observability-otel/src/modules/agent-signal
Treat this as shared OTEL ownership for Agent Signal metrics and tracer instances.
Core Vocabulary
Source
A source is the normalized external fact that started the chain.
Examples:
agent.user.messageruntime.before_stepruntime.after_stepclient.runtime.startbot.message.merged
Define source payloads in:
apps/server/src/services/agentSignal/sourceTypes.ts
Build normalized sources in:
apps/server/src/services/agentSignal/sources/buildSource.tspackages/agent-signal/src/base/builders.ts
Signal
A signal is a semantic interpretation. Signals should be reusable and meaning-oriented.
Examples from analyzeIntent:
signal.feedback.satisfactionsignal.feedback.domain.memorysignal.feedback.domain.promptsignal.feedback.domain.skill
Define server-owned signal types in:
apps/server/src/services/agentSignal/policies/types.ts
Action
An action is a concrete side effect the runtime should execute.
Example:
action.user-memory.handle
Action handlers usually:
- check idempotency
- call tools, models, or services
- return
ExecutorResult
Policy
A policy is an installable bundle of handlers. It is the composition unit that turns the generic runtime into a feature.
Example:
createAnalyzeIntentPolicy(...)
Procedure
"Procedure" is not a first-class type in this runtime. Use the word to describe one end-to-end use case:
1. define ingress source 2. emit or enqueue the source 3. interpret source into signals 4. plan actions from signals 5. execute actions 6. persist trace and metrics
When a user asks for "the procedure", document the flow above and point to the exact producer, handlers, and execution entrypoint.
Scope, Deduping, And Quiet Background Work
scopeKey is the serialization boundary for related work. It is used for:
- source dedupe windows
- scope locks during source generation
- runtime guard state
- waypoint persistence for queued processing
Read:
apps/server/src/services/agentSignal/sources/index.tsapps/server/src/services/agentSignal/runtime/context.tsapps/server/src/services/agentSignal/constants.ts
Use enqueueAgentSignalSourceEvent(...) when the work should stay quiet and out-of-band. That path:
1. normalizes the source envelope 2. derives or reuses scopeKey 3. triggers AgentSignalWorkflow 4. executes later in runAgentSignalWorkflow
This is the preferred path when the UI request should finish immediately and the policy can run in the background.
Read:
apps/server/src/workflows/agentSignal/index.tsapps/server/src/workflows/agentSignal/run.ts
Existing Example: analyzeIntent
Use analyzeIntent as the reference chain:
agent.user.message
-> feedback satisfaction source handler
-> signal.feedback.satisfaction
-> feedback domain signal handler
-> signal.feedback.domain.*
-> feedback action planner
-> action.user-memory.handle
-> signal.action.applied | skipped | failedRead:
apps/server/src/services/agentSignal/policies/analyzeIntent/index.tsapps/server/src/services/agentSignal/policies/analyzeIntent/feedbackSatisfaction.tsapps/server/src/services/agentSignal/policies/analyzeIntent/feedbackDomain.tsapps/server/src/services/agentSignal/policies/analyzeIntent/feedbackAction.tsapps/server/src/services/agentSignal/policies/analyzeIntent/actions/userMemory.ts
Writing Handlers And Policies
Fluent Registration API
Use the middleware helpers in apps/server/src/services/agentSignal/runtime/middleware.ts.
They provide:
defineSourceHandler(...)defineSignalHandler(...)defineActionHandler(...)defineAgentSignalHandlers(...)
These helpers do two jobs:
1. keep handler registration terse 2. preserve strong typing when listen points at concrete source, signal, or action types
Handler Shape
Each handler receives:
- the current runtime node
RuntimeProcessorContext
The context gives you:
scopeKeynow()runtimeState.getGuardState(lane)runtimeState.touchGuardState(lane, now?)
Read:
apps/server/src/services/agentSignal/runtime/context.ts
Return Contracts
Return one of these shapes:
void: no fan-out, stop at this handler{ status: 'dispatch', signals?, actions? }: continue the chain{ status: 'wait', pending? }: pause for later host coordination{ status: 'schedule', nextHop }: schedule another hop{ status: 'conclude', concluded? }: stop with a terminal runtime resultExecutorResult: only for action handlers that performed a concrete side effect
Read:
packages/agent-signal/src/base/types.tsapps/server/src/services/agentSignal/runtime/AgentSignalScheduler.ts
Policy Composition Pattern
Use defineAgentSignalHandlers([...]) to bundle related handlers into one policy.
Example from analyzeIntent:
return defineAgentSignalHandlers([
createFeedbackSatisfactionJudgeProcessor(...),
createFeedbackDomainJudgeSignalHandler(...),
createFeedbackActionPlannerSignalHandler(),
defineUserMemoryActionHandler(...),
]);That bundle is later passed into the runtime via:
createDefaultAgentSignalPolicies(...)createAgentSignalRuntime({ policies })
Read:
apps/server/src/services/agentSignal/policies/index.tsapps/server/src/services/agentSignal/policies/analyzeIntent/index.ts
Source Handler Pattern
Use a source handler when you are interpreting a producer event into semantic signals.
Reference:
apps/server/src/services/agentSignal/policies/analyzeIntent/feedbackSatisfaction.ts
Pattern:
return defineSourceHandler(
AGENT_SIGNAL_SOURCE_TYPES.agentUserMessage,
'agent.user.message:my-handler',
async (source, ctx): Promise<RuntimeProcessorResult | void> => {
// interpret source payload
// optionally use ctx.runtimeState
return {
signals: [
/* one or more semantic signals */
],
status: 'dispatch',
};
},
);Write source handlers when:
- a raw message, lifecycle event, or bot ingress needs interpretation
- the work is still semantic, not side-effectful
Signal Handler Pattern
Use a signal handler when one semantic state should branch into more semantic states or planned actions.
References:
apps/server/src/services/agentSignal/policies/analyzeIntent/feedbackDomain.tsapps/server/src/services/agentSignal/policies/analyzeIntent/feedbackAction.ts
Pattern:
return defineSignalHandler(
MY_SIGNAL_TYPE,
'signal.my-policy-router',
async (signal): Promise<RuntimeProcessorResult | void> => {
return {
actions: [
/* planned work */
],
status: 'dispatch',
};
},
);Use signal handlers for:
- routing
- fan-out
- filtering
- conflict resolution
- converting interpretation into planned actions
Action Handler Pattern
Use an action handler when the runtime should do actual work.
Reference:
apps/server/src/services/agentSignal/policies/analyzeIntent/actions/userMemory.ts
Pattern:
return defineActionHandler(
MY_ACTION_TYPE,
'action.my-policy-executor',
async (action, ctx): Promise<ExecutorResult> => {
// run service/tool/model side effect
// check idempotency if needed
return {
actionId: action.actionId,
attempt: {
completedAt: ctx.now(),
current: 1,
startedAt,
status: 'succeeded',
},
status: 'applied',
};
},
);Keep these rules:
- perform idempotency checks here or immediately before side effects
- return stable
actionId - include failure detail in
error - let the scheduler turn the
ExecutorResultinto built-in result signals
Source, Signal, And Action Type Placement
Use this split:
- external event payloads:
apps/server/src/services/agentSignal/sourceTypes.ts
- policy-owned signal and action payloads:
apps/server/src/services/agentSignal/policies/types.ts
- normalized shared node contracts:
packages/agent-signal/src/base/types.ts
Do not put app-specific signal catalogs into packages/agent-signal. That package should stay generic and reusable.
Choosing The Right Node
Choose source when:
- the outside world emitted a new fact
Choose signal when:
- the system needs semantic meaning that downstream handlers can reuse
Choose action when:
- the runtime is ready for a concrete side effect
If a handler both interprets meaning and performs side effects, split it. That keeps chains inspectable and testable.
Testing Strategy
Prefer focused tests near the touched code.
Useful references:
apps/server/src/services/agentSignal/runtime/__tests__/AgentSignalRuntime.test.tsapps/server/src/services/agentSignal/__tests__/index.integration.test.tsapps/server/src/services/agentSignal/policies/analyzeIntent/__tests__/*apps/server/src/services/agentSignal/policies/analyzeIntent/actions/__tests__/*
Test at the smallest level that proves the behavior:
- handler unit test for one routing rule
- runtime test for queue fan-out
- integration test for service ingress and observability persistence
Observability And Debugging
OTEL Ownership
Use packages/observability-otel/src/modules/agent-signal/index.ts for the shared tracer and metrics.
Available instruments:
tracersourceCountersignalCounteractionCounteractionResultCounterchainCountersignalActionTransitionCounterchainDurationHistogramactionDurationHistogram
Use this module when you need shared telemetry ownership instead of creating feature-local meters or tracers.
Projection Pipeline
After runtime execution, the service projects one compact observability model from the full chain.
Read:
apps/server/src/services/agentSignal/observability/projector.tsapps/server/src/services/agentSignal/observability/traceEvents.tsapps/server/src/services/agentSignal/observability/store.ts
Projection outputs:
- a trace envelope with source, signals, actions, results, edges, and handler runs
- a compact telemetry record with dominant path, status breakdown, and chain metadata
This projection is built from:
- source node
- emitted signals
- planned actions
- executor results
How To Inspect A Chain
Use this order:
1. Inspect the source type and payload. 2. Inspect emitted signals. 3. Inspect planned actions. 4. Inspect executor results. 5. Inspect projected edges and dominant path.
The helper toAgentSignalTraceEvents(...) flattens a chain into compact event records suitable for tracing snapshots.
Workflow Snapshot Bridge
Workflow-triggered runs do not naturally pass through the normal foreground runtime snapshot path, so runAgentSignalWorkflow adds a development-only bridge into .agent-tracing/.
Read:
apps/server/src/workflows/agentSignal/run.ts
Use that path when:
- the source was enqueued with
enqueueAgentSignalSourceEvent(...) - you need local trace visibility for quiet background work
Common Debug Questions
The source emits but nothing happens
Check:
- feature gate enabled for the user
- source type matches a registered source handler
- dedupe or scope lock did not short-circuit generation
Read:
apps/server/src/services/agentSignal/index.tsapps/server/src/services/agentSignal/sources/index.ts
The signal exists but no action runs
Check:
- the signal type has a registered signal handler
- the signal handler returns
status: 'dispatch' - the handler actually returned actions
The action runs twice
Check:
- source dedupe key stability
- action idempotency strategy
- scope key stability across retries and workflow handoff
Reference:
apps/server/src/services/agentSignal/policies/actionIdempotency.tsapps/server/src/services/agentSignal/policies/analyzeIntent/actions/userMemory.ts
Background runs are hard to discover
Check:
- workflow snapshot bridge in development
- projected telemetry record contents
- OTEL counters and histograms in the shared module
Minimal Completion Checklist
- source ingress is testable
- handler registration is discoverable from the policy factory
- action executor returns structured results
- projection includes the new path cleanly
- tests cover at least one happy path and one no-op or failure path