diff --git a/cmd/claw-wall/store.go b/cmd/claw-wall/store.go
index e9d61d3..09b2f8c 100644
--- a/cmd/claw-wall/store.go
+++ b/cmd/claw-wall/store.go
@@ -17,7 +17,7 @@ const (
backgroundContextSize = 10
defaultTailLimit = 40
defaultAwarenessLimit = 60
- defaultTailMaxChars = 8 * 1024
+ defaultTailMaxChars = 32 * 1024
)
const (
diff --git a/cmd/claw/compose_up.go b/cmd/claw/compose_up.go
index 2a8827b..81bba69 100644
--- a/cmd/claw/compose_up.go
+++ b/cmd/claw/compose_up.go
@@ -49,7 +49,7 @@ const (
conversationWallFeedSince = "24h"
conversationWallFeedLimit = 40
conversationWallAwarenessLimit = 60
- conversationWallFeedMaxChars = 8 * 1024
+ conversationWallFeedMaxChars = 32 * 1024
conversationWallBufferLimit = 5000
conversationWallPollInterval = "30"
conversationWallRetention = "24h"
@@ -1810,7 +1810,7 @@ func injectConversationWall(p *pod.Pod, resolvedClaws map[string]*driver.Resolve
continue
}
settings := conversationWallChannelContext(p, svc)
- awarenessSettings := conversationWallChannelAwarenessContext()
+ awarenessSettings := conversationWallChannelAwarenessContext(p, svc)
svc.Claw.Feeds = appendConversationWallAwarenessFeed(svc.Claw.Feeds, channelIDs, awarenessSettings)
svc.Claw.Feeds = appendConversationWallFeed(svc.Claw.Feeds, channelIDs, settings)
svc.Claw.Tools = appendConversationWallToolPolicy(svc.Claw.Tools)
@@ -1898,12 +1898,19 @@ func conversationWallChannelContext(p *pod.Pod, svc *pod.Service) conversationWa
return settings
}
-func conversationWallChannelAwarenessContext() conversationWallContextSettings {
- return conversationWallContextSettings{
+func conversationWallChannelAwarenessContext(p *pod.Pod, svc *pod.Service) conversationWallContextSettings {
+ settings := conversationWallContextSettings{
Since: conversationWallFeedSince,
Limit: conversationWallAwarenessLimit,
MaxChars: conversationWallFeedMaxChars,
}
+ if p != nil && p.Context != nil {
+ settings = applyConversationWallChannelContext(settings, p.Context.Channel)
+ }
+ if svc != nil && svc.Claw != nil && svc.Claw.Context != nil {
+ settings = applyConversationWallChannelContext(settings, svc.Claw.Context.Channel)
+ }
+ return settings
}
func applyConversationWallChannelContext(settings conversationWallContextSettings, cfg *pod.ChannelContextConfig) conversationWallContextSettings {
diff --git a/cmd/claw/compose_up_test.go b/cmd/claw/compose_up_test.go
index 9f937e3..57a105d 100644
--- a/cmd/claw/compose_up_test.go
+++ b/cmd/claw/compose_up_test.go
@@ -3209,7 +3209,7 @@ func TestBuildFeedManifestUsesOrdinalClawID(t *testing.T) {
{
Name: conversationWallFeedName,
Source: conversationWallServiceName,
- Path: "/channel-context?consumer={claw_id}&channels=chan-a,chan-b&mode=tail&since=24h&limit=40&max_chars=8192",
+ Path: "/channel-context?consumer={claw_id}&channels=chan-a,chan-b&mode=tail&since=24h&limit=40&max_chars=32768",
TTL: conversationWallFeedTTL,
},
},
@@ -3225,10 +3225,10 @@ func TestBuildFeedManifestUsesOrdinalClawID(t *testing.T) {
if len(feeds) != 1 {
t.Fatalf("expected one feed, got %d", len(feeds))
}
- if feeds[0].Path != "/channel-context?consumer=trader-1&channels=chan-a,chan-b&mode=tail&since=24h&limit=40&max_chars=8192" {
+ if feeds[0].Path != "/channel-context?consumer=trader-1&channels=chan-a,chan-b&mode=tail&since=24h&limit=40&max_chars=32768" {
t.Fatalf("expected ordinal claw_id substitution, got %q", feeds[0].Path)
}
- if feeds[0].URL != "http://claw-wall:8080/channel-context?consumer=trader-1&channels=chan-a,chan-b&mode=tail&since=24h&limit=40&max_chars=8192" {
+ if feeds[0].URL != "http://claw-wall:8080/channel-context?consumer=trader-1&channels=chan-a,chan-b&mode=tail&since=24h&limit=40&max_chars=32768" {
t.Fatalf("expected ordinal wall URL, got %q", feeds[0].URL)
}
}
@@ -3938,14 +3938,14 @@ func TestInjectConversationWallAddsServiceAndFeed(t *testing.T) {
if awarenessFeed.Source != conversationWallServiceName {
t.Fatalf("expected claw-wall awareness source, got %+v", awarenessFeed)
}
- if awarenessFeed.Path != "/channel-awareness?channels=chan-1,chan-2&since=24h&limit=60&max_chars=8192&context_kind=raw_window" {
+ if awarenessFeed.Path != "/channel-awareness?channels=chan-1,chan-2&since=24h&limit=60&max_chars=32768&context_kind=raw_window" {
t.Fatalf("unexpected awareness feed path: %q", awarenessFeed.Path)
}
contextFeed := testFeedByName(t, traderFeeds, conversationWallFeedName)
if contextFeed.Source != conversationWallServiceName {
t.Fatalf("expected claw-wall context source, got %+v", contextFeed)
}
- if contextFeed.Path != "/channel-context?consumer={claw_id}&channels=chan-1,chan-2&mode=tail&since=24h&limit=40&max_chars=8192" {
+ if contextFeed.Path != "/channel-context?consumer={claw_id}&channels=chan-1,chan-2&mode=tail&since=24h&limit=40&max_chars=32768" {
t.Fatalf("unexpected wall feed path: %q", contextFeed.Path)
}
traderTools := p.Services["trader"].Claw.Tools
@@ -3999,7 +3999,7 @@ func TestInjectConversationWallHonorsChannelContextConfig(t *testing.T) {
t.Fatalf("expected trader feed, got %+v", traderFeeds)
}
traderAwareness := testFeedByName(t, traderFeeds, conversationWallAwarenessName)
- if traderAwareness.Path != "/channel-awareness?channels=chan-1&since=24h&limit=60&max_chars=8192&context_kind=raw_window" {
+ if traderAwareness.Path != "/channel-awareness?channels=chan-1&since=6h&limit=25&max_chars=4096&context_kind=raw_window" {
t.Fatalf("unexpected trader awareness path: %q", traderAwareness.Path)
}
traderContext := testFeedByName(t, traderFeeds, conversationWallFeedName)
@@ -4012,7 +4012,7 @@ func TestInjectConversationWallHonorsChannelContextConfig(t *testing.T) {
t.Fatalf("expected scout feed, got %+v", scoutFeeds)
}
scoutAwareness := testFeedByName(t, scoutFeeds, conversationWallAwarenessName)
- if scoutAwareness.Path != "/channel-awareness?channels=chan-1&since=24h&limit=60&max_chars=8192&context_kind=raw_window" {
+ if scoutAwareness.Path != "/channel-awareness?channels=chan-1&since=30m&limit=8&max_chars=1024&context_kind=raw_window" {
t.Fatalf("unexpected scout awareness path: %q", scoutAwareness.Path)
}
scoutContext := testFeedByName(t, scoutFeeds, conversationWallFeedName)
diff --git a/cmd/claw/skill_data/SKILL.md b/cmd/claw/skill_data/SKILL.md
index 565a495..0449712 100644
--- a/cmd/claw/skill_data/SKILL.md
+++ b/cmd/claw/skill_data/SKILL.md
@@ -389,7 +389,7 @@ The proxy sits between agents and LLM providers. Agents get bearer tokens, proxy
### claw-wall sidecar
-Auto-injected by `claw up` when any cllama-enabled service has Discord channel IDs. Polls Discord channels and serves the recent channel transcript to agents through `channel-context` tail feeds; legacy unread-mailbox cursor paging remains available as `mode=delta`. On startup, wall backfills Discord history before its first forward poll up to `CLAW_WALL_RETENTION` (default `24h`) and `CLAW_WALL_BACKFILL_MAX_PAGES` (default `25`), while `CLAW_WALL_LIMIT` is a per-channel safety cap (default `5000`). Configure the generated tail window with pod or service `x-claw.context.channel` (`since`, `limit`, `max-chars`, `buffer`). Since `v0.15.0` channel-consuming services also get a default-on `channel-awareness` feed (uncursored 24h raw window, internally bounded) plus two cllama-mediated retrieval tools - `search_channel_context` and `get_channel_messages` - auto-subscribed via a compiler-owned claw-wall descriptor. Feed headers include `backfill_status`; `partial` or `rate_limited` means the backing window did not fully satisfy the requested horizon. Calls are gated by a generated per-agent channel allowlist, claw-wall service-token auth, and forwarded `X-Claw-ID`. The service name `claw-wall` is reserved - declaring it in `claw-pod.yml` is a hard error.
+Auto-injected by `claw up` when any cllama-enabled service has Discord channel IDs. Polls Discord channels and serves the recent channel transcript to agents through `channel-context` tail feeds; legacy unread-mailbox cursor paging remains available as `mode=delta`. On startup, wall backfills Discord history before its first forward poll up to `CLAW_WALL_RETENTION` (default `24h`) and `CLAW_WALL_BACKFILL_MAX_PAGES` (default `25`), while `CLAW_WALL_LIMIT` is a per-channel safety cap (default `5000`). Configure the generated tail window with pod or service `x-claw.context.channel` (`since`, `limit`, `max-chars`, `buffer`). Since `v0.15.0` channel-consuming services also get a default-on `channel-awareness` feed (uncursored 24h raw window; `x-claw.context.channel.max-chars` tunes both feeds together, default 32 KB) plus two cllama-mediated retrieval tools - `search_channel_context` and `get_channel_messages` - auto-subscribed via a compiler-owned claw-wall descriptor. Feed headers include `backfill_status`; `partial` or `rate_limited` means the backing window did not fully satisfy the requested horizon. Calls are gated by a generated per-agent channel allowlist, claw-wall service-token auth, and forwarded `X-Claw-ID`. The service name `claw-wall` is reserved - declaring it in `claw-pod.yml` is a hard error.
## Generated Artifacts
diff --git a/site/changelog.md b/site/changelog.md
index ec1b7fa..1035f80 100644
--- a/site/changelog.md
+++ b/site/changelog.md
@@ -29,7 +29,7 @@ outline: deep
## Unreleased
-
+- **Channel feeds carry the whole conversation, not just the tail** — the default `max_chars` cap on both `channel-context` and `channel-awareness` feeds is raised from 8 KB to 32 KB so 24h on a modestly-active channel actually fits, and `channel-awareness` now honors the existing `x-claw.context.channel` tuning block (pod and service level). One knob raises both feeds together; busy production rooms can crank `max-chars` to 64-256 KB so the awareness surface covers a meaningful slice of the day rather than the last handful of messages. Closes [#242](https://github.com/mostlydev/clawdapus/issues/242).
## v0.17.1 {#v0-17-1}
diff --git a/site/guide/pod-yaml.md b/site/guide/pod-yaml.md
index 6e673db..a9590b4 100644
--- a/site/guide/pod-yaml.md
+++ b/site/guide/pod-yaml.md
@@ -211,20 +211,20 @@ services:
## Channel Context Tuning
-When any cllama-enabled service has Discord channels in its handles, `claw up` auto-injects the `claw-wall` sidecar and a `channel-context` feed for each consuming agent. The feed serves the recent room transcript so a mentioned agent sees the conversation that prompted it (see [Social Topology · Channel Context Feed](/guide/social-topology#channel-context-feed-claw-wall)). Tune the generated tail with `x-claw.context.channel`:
+When any cllama-enabled service has Discord channels in its handles, `claw up` auto-injects the `claw-wall` sidecar plus two feeds for each consuming agent: `channel-context` (cursored delta tail, mention/turn context) and `channel-awareness` (uncursored last-24h raw window, always-on memory of the room). Both feeds share the same tuning knob — see [Social Topology · Channel Context Feed](/guide/social-topology#channel-context-feed-claw-wall). Tune them with `x-claw.context.channel`:
```yaml
x-claw:
pod: trading-desk
context:
channel:
- since: 24h # window covered by the tail (default 24h)
- limit: 40 # max messages returned (default 40)
- max-chars: 8192 # byte cap on rendered body (default 8192)
- buffer: 5000 # per-channel safety cap in the wall sidecar (default 5000)
+ since: 24h # window covered by the feeds (default 24h)
+ limit: 40 # max messages returned (default: 40 for channel-context, 60 for channel-awareness)
+ max-chars: 32768 # byte cap on rendered body (default 32 KB)
+ buffer: 5000 # per-channel safety cap in the wall sidecar (default 5000)
```
-Service-level `x-claw.context.channel` overrides pod-level values for that service. `buffer` is shared across the pod, so when services disagree the largest value wins, with the built-in 5000-message floor still applied. `since` accepts any Go duration (`30m`, `2h15m`, `24h`). Set `max_chars` if you prefer the underscore alias; mixing the two with conflicting values is a parse error.
+Service-level `x-claw.context.channel` overrides pod-level values for that service. The same block tunes both `channel-context` and `channel-awareness` — busy production rooms typically want `max-chars` somewhere in the 64-256 KB range so the 24h awareness feed actually covers a meaningful slice of the day rather than the last handful of messages. `buffer` is shared across the pod, so when services disagree the largest value wins, with the built-in 5000-message floor still applied. `since` accepts any Go duration (`30m`, `2h15m`, `24h`). Set `max_chars` if you prefer the underscore alias; mixing the two with conflicting values is a parse error.
The wall serves `mode=tail` (non-consuming, latest-N walk) by default. Starting in v0.14.0, cllama drives the feed as a delta-since-watermark by adding `after=:` cursors to the URL, so each turn fetches only new messages instead of re-pasting the full tail. `since` and `limit` from `x-claw.context.channel` remain the bootstrap and dual-cap bounds. The wall's retention horizon and startup backfill budget are sidecar env settings (`CLAW_WALL_RETENTION`, `CLAW_WALL_BACKFILL_MAX_PAGES`) rather than pod-YAML schema. See [Social Topology · Cursored Append-Only Deltas](/guide/social-topology#cursored-append-only-deltas) for the proxy-side model. The legacy cursor/mailbox path remains callable as `mode=delta` for any consumer that genuinely wants oldest-unread paging; generated feeds do not use it.
diff --git a/skills/clawdapus/SKILL.md b/skills/clawdapus/SKILL.md
index 565a495..0449712 100644
--- a/skills/clawdapus/SKILL.md
+++ b/skills/clawdapus/SKILL.md
@@ -389,7 +389,7 @@ The proxy sits between agents and LLM providers. Agents get bearer tokens, proxy
### claw-wall sidecar
-Auto-injected by `claw up` when any cllama-enabled service has Discord channel IDs. Polls Discord channels and serves the recent channel transcript to agents through `channel-context` tail feeds; legacy unread-mailbox cursor paging remains available as `mode=delta`. On startup, wall backfills Discord history before its first forward poll up to `CLAW_WALL_RETENTION` (default `24h`) and `CLAW_WALL_BACKFILL_MAX_PAGES` (default `25`), while `CLAW_WALL_LIMIT` is a per-channel safety cap (default `5000`). Configure the generated tail window with pod or service `x-claw.context.channel` (`since`, `limit`, `max-chars`, `buffer`). Since `v0.15.0` channel-consuming services also get a default-on `channel-awareness` feed (uncursored 24h raw window, internally bounded) plus two cllama-mediated retrieval tools - `search_channel_context` and `get_channel_messages` - auto-subscribed via a compiler-owned claw-wall descriptor. Feed headers include `backfill_status`; `partial` or `rate_limited` means the backing window did not fully satisfy the requested horizon. Calls are gated by a generated per-agent channel allowlist, claw-wall service-token auth, and forwarded `X-Claw-ID`. The service name `claw-wall` is reserved - declaring it in `claw-pod.yml` is a hard error.
+Auto-injected by `claw up` when any cllama-enabled service has Discord channel IDs. Polls Discord channels and serves the recent channel transcript to agents through `channel-context` tail feeds; legacy unread-mailbox cursor paging remains available as `mode=delta`. On startup, wall backfills Discord history before its first forward poll up to `CLAW_WALL_RETENTION` (default `24h`) and `CLAW_WALL_BACKFILL_MAX_PAGES` (default `25`), while `CLAW_WALL_LIMIT` is a per-channel safety cap (default `5000`). Configure the generated tail window with pod or service `x-claw.context.channel` (`since`, `limit`, `max-chars`, `buffer`). Since `v0.15.0` channel-consuming services also get a default-on `channel-awareness` feed (uncursored 24h raw window; `x-claw.context.channel.max-chars` tunes both feeds together, default 32 KB) plus two cllama-mediated retrieval tools - `search_channel_context` and `get_channel_messages` - auto-subscribed via a compiler-owned claw-wall descriptor. Feed headers include `backfill_status`; `partial` or `rate_limited` means the backing window did not fully satisfy the requested horizon. Calls are gated by a generated per-agent channel allowlist, claw-wall service-token auth, and forwarded `X-Claw-ID`. The service name `claw-wall` is reserved - declaring it in `claw-pod.yml` is a hard error.
## Generated Artifacts