DeepSeek Harness: Service Isolation and Scope
Last updated: 2026-08-31
In multi-Agent, multi-session environments, shared services are both a blessing and a curse — global services are convenient but conflict-prone, isolated services are safe but communication costs more. Cordis's scope system balances both: shared by default, isolated on demand.
📋 Prerequisites: Completed 19-service.md, understand the Service base class
1. What You'll Learn
- Global Scope
- Session Scope
- Request Scope
- isolate realm configuration
- Scope and Agent presets
- Multi-Agent service isolation
2. Global Scope
(1) Default Behavior
By default, all Services are global — there's only one instance across the entire DSH instance:
export default class CacheService extends Service {
constructor(ctx: Context) {
super(ctx, 'cache') // Globally unique
}
}
(2) Global Service Characteristics
| Characteristic | Description |
|---|---|
| Singleton | Only one instance per process |
| Shared | All sessions and requests share the same state |
| No isolation | Data modified by session A is visible to session B |
(3) Applicable Scenarios
- Configuration management (only one global config needed)
- Connection pools (shared connections are more efficient)
- Logging services (logs should be centrally collected)
- Model adapters (API calls can be reused across sessions)
(4) ▶ Example 4
// ❌ Global cache causes cross-session data leakage
export default class CacheService extends Service {
private data = new Map<string, any>()
set(key: string, value: any) {
this.data.set(key, value)
}
}
// Session A: ctx.cache.set('temp', 'secret-data')
// Session B: ctx.cache.get('temp') → 'secret-data' (leaked!)
3. Session Scope
(1) Concept
Session scope creates an independent service instance for each session:
export default class SessionCacheService extends Service {
static scope = 'session'
constructor(ctx: Context) {
super(ctx, 'session-cache')
}
}
(2) ▶ Example 2
graph LR
S1[Session A created] --> C1[CacheService A instance]
S2[Session B created] --> C2[CacheService B instance]
S1 --> D1[Session A destroyed → CacheService A destroyed]
S2 --> D2[Session B destroyed → CacheService B destroyed]
(3) Scope Declaration
export default class SessionCacheService extends Service {
static scope = 'session'
// Or
// static scope = Symbol('session')
}
(4) Applicable Scenarios
- Session-level cache
- Session-level config overrides
- Session-level tool set customization
- Session history
(5) Cross-Session Isolation Effect
Session A:
ctx.sessionCache.set('key', 'value-A')
Session B:
ctx.sessionCache.get('key') → undefined (isolated)
Session A:
ctx.sessionCache.get('key') → 'value-A' (accessible within session)
4. Request Scope
(1) Concept
Request scope creates an independent instance for each tool call or LLM request:
export default class RequestContextService extends Service {
static scope = 'request'
constructor(ctx: Context) {
super(ctx, 'request-context')
}
}
(2) Request Scope Lifecycle
graph LR
R1[Request 1 starts] --> S1[Service instance 1]
R2[Request 2 starts] --> S2[Service instance 2]
R1 --> E1[Request 1 completes → instance 1 destroyed]
R2 --> E2[Request 2 completes → instance 2 destroyed]
(3) Applicable Scenarios
- Request-level context info (user IP, request ID)
- Request-level permission checks
- Request-level performance timing
- Request-level log aggregation
(4) Three Scope Levels Comparison
| Dimension | Global | Session | Request |
|---|---|---|---|
| Instances | 1 | 1 per session | 1 per request |
| Lifecycle | Process lifetime | Session lifetime | Request lifetime |
| State sharing | Globally shared | Within session | Within request only |
| Memory | Low | Medium | High |
| Best for | Config/connection pools | Session cache/history | Permissions/timing |
5. isolate Realm Configuration
(1) Realm Concept
A realm is Cordis's isolation domain — creating independent plugin spaces within the same DSH instance:
# cordis.yml
realms:
agent-a:
isolate: ['cache', 'tools']
plugins:
my-tool-a:
$insert: ./plugins/tool-a
agent-b:
isolate: ['cache', 'tools']
plugins:
my-tool-b:
$insert: ./plugins/tool-b
(2) isolate Field
The isolate list specifies which services get independent instances within the realm:
realms:
my-realm:
isolate:
- cache # cache service gets independent instance
- tools # tools service gets independent instance
# Services not listed remain globally shared
(3) Service Instances Within a Realm
Global: llm (shared)
realm-a: cache (independent), tools (independent)
realm-b: cache (independent), tools (independent)
Plugins in realm-a → ctx.cache = realm-a's cache
Plugins in realm-b → ctx.cache = realm-b's cache
They don't affect each other
(4) Realm Use Cases
| Scenario | Description |
|---|---|
| Multi-Agent | Different Agents have different tool sets and caches |
| Multi-tenant | Different tenants' services are mutually isolated |
| Testing | Test realm doesn't affect production realm |
| A/B testing | Two realms use different service implementations |
(5) Cross-Realm Communication
Realms are isolated by default but can communicate through global services:
// Global service (unaffected by isolate)
export default class EventBusService extends Service {
constructor(ctx: Context) {
super(ctx, 'event-bus') // Not in isolate list → globally shared
}
emit(event: string, data: any) { /* ... */ }
on(event: string, handler: Function) { /* ... */ }
}
// Plugin in realm-a
ctx.eventBus.emit('data-updated', { source: 'realm-a' })
// Plugin in realm-b
ctx.eventBus.on('data-updated', (data) => {
ctx.logger.info(`received from ${data.source}`)
})
6. Scope and Agent Presets
(1) Agent Preset Concept
An Agent preset is a pre-defined Agent configuration including tool set, model parameters, and scope settings:
presets:
coder:
model: deepseek-coder
tools: [file_edit, shell, search]
mode: standard
reviewer:
model: deepseek-chat
tools: [file_edit, search]
mode: minimal
isolate: [cache]
(2) Preset and Scope Relationship
Each preset can specify an isolate list, creating isolated service instances for that Agent:
coder Agent: shared cache, independent tools
reviewer Agent: independent cache, shared tools
(3) Multi-Agent Scenario
# cordis.yml
agents:
coder:
preset: coder
isolate: [tools]
reviewer:
preset: reviewer
isolate: [tools, cache]
(4) Inter-Agent Collaboration
graph TB
subgraph Global
LLM[llm Service]
EVENT[event-bus Service]
end
subgraph Agent-Coder
CT[tools Service]
CC[cache Service]
end
subgraph Agent-Reviewer
RT[tools Service]
RC[cache Service]
end
CT --> LLM
RT --> LLM
CT --> EVENT
RT --> EVENT
7. Multi-Agent Service Isolation
(1) Isolation Strategy Selection
Fully shared: All services global → simple but potential conflicts
Fully isolated: All services independent → safe but resource waste
Mixed isolation: Core services shared + business services isolated → balanced approach
Recommended mixed isolation:
| Service Type | Isolation Strategy | Reason |
|---|---|---|
| llm | Shared | API calls can be reused |
| sessions | Shared | Unified session management |
| tools | Isolated | Each Agent has different tool sets |
| cache | Isolated | Each Agent has independent cache |
| fs | Shared | Only one filesystem |
(2) ▶ Example 2
agents:
frontend-dev:
preset: coder
isolate: [tools, cache]
tools:
- file_edit
- shell
- search
config:
cache:
maxSize: 100
backend-dev:
preset: coder
isolate: [tools, cache]
tools:
- file_edit
- shell
- search
- database
config:
cache:
maxSize: 200
(3) Resource Consumption Estimation
| Isolation Level | Memory | CPU | Connections |
|---|---|---|---|
| Global shared | 1x | 1x | 1x |
| 2-Agent isolated | ~2x | ~1.5x | ~2x |
| 5-Agent isolated | ~5x | ~3x | ~5x |
(4) Isolation Leak Detection
// Monitor service instance counts
ctx.on('service/created', (name, instance) => {
ctx.logger.info(`service created: ${name}, total instances: ${countInstances(name)}`)
})
// If a service's instance count far exceeds the Agent count, there may be a leak
❓ FAQ
static scope is a global singleton by default.typescript constructor(ctx: Context) { super(ctx, 'cache') console.log(`cache instance created: ${this.id}, scope: ${this.scope}`) } 📖 Summary
- Three scope levels: global (default), session (independent per session), request (independent per request)
- Global services suit config/connection pools, session services suit cache/history, request services suit permissions/timing
- isolate realm configuration creates independent service instances for specific spaces
- Agent presets combined with scope enable multi-Agent tool set and cache isolation
- Recommended mixed isolation strategy: core services shared + business services isolated
- Scope choice affects memory and performance; isolate on demand, don't overdo it
📝 Exercises
1. ⭐ Basic: Write a session-scoped SessionStateService that maintains independent key-value storage per session. Start two sessions and verify data isolation.
2. ⭐⭐ Intermediate: Configure a realm that isolates cache and tools services. Access cache both inside and outside the realm, verifying you get different instances.
3. ⭐⭐⭐ Challenge: Design a dual-Agent system: coder and reviewer. Coder has file_edit/shell tools, reviewer only has file_edit/search tools. Both share llm and sessions, but cache and tool sets are independently isolated. Verify: coder's shell tool is invisible to reviewer, and their caches don't affect each other.