Skip to content

feat(cortex): add self-awareness docs and config diagnostics#311

Merged
jamiepine merged 6 commits intomainfrom
self-awareness
Mar 4, 2026
Merged

feat(cortex): add self-awareness docs and config diagnostics#311
jamiepine merged 6 commits intomainfrom
self-awareness

Conversation

@jamiepine
Copy link
Member

@jamiepine jamiepine commented Mar 4, 2026

Summary

  • add a new self_awareness module that embeds Spacebot self-knowledge (AGENTS.md, seeded CHANGELOG.md, static repo docs, and all docs/content markdown) and injects it into cortex chat with a live redacted runtime-config snapshot
  • add spacebot_docs (branch + cortex chat) and config_inspect (cortex chat) tools, plus prompt/docs updates so agents use source docs and live config for diagnostics
  • update release workflow to maintain CHANGELOG.md through cargo bump: scripts/release-tag.sh now generates GitHub-native notes and requires a per-release marketing story; add .agents/skills/release-bump-changelog to standardize that flow

Validation

  • ./scripts/preflight.sh
  • ./scripts/gate-pr.sh

Note

AI-Generated Summary

This PR equips the cortex process with self-awareness by embedding architectural documentation and exposing live configuration state. New tools allow the cortex and branches to query system architecture (via spacebot_docs) and inspect runtime config (via config_inspect). The release workflow now generates versioned changelog entries combining marketing narrative with GitHub-native release notes, standardized through a new skill.
Written by Tembo for commit 33a6a0c. This will update automatically on new commits.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 4, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a self-awareness module embedding docs and changelog, two runtime tools (spacebot_docs, config_inspect), augments cortex prompt context with manifest and runtime snapshots, updates tool-server wiring to accept RuntimeConfig, and enhances release tooling and CHANGELOG management plus a release-skill doc. (49 words)

Changes

Cohort / File(s) Summary
Self-awareness module
src/self_awareness.rs, src/lib.rs
New self_awareness module embedding docs and CHANGELOG; exposes agents_manifest, changelog_highlights, runtime snapshot/value, doc catalog/search/read APIs, public types, and tests.
New tools & wiring
src/tools/spacebot_docs.rs, src/tools/config_inspect.rs, src/tools.rs
Adds spacebot_docs (list/read embedded docs) and config_inspect (redacted runtime-config inspection); re-exports tool types and registers tools on branch and cortex tool servers; create_cortex_chat_tool_server signature now accepts runtime_config: Arc<RuntimeConfig>.
Cortex prompt & prompt engine
src/agent/cortex_chat.rs, src/prompts/engine.rs, src/prompts/text.rs
Cortex prompt rendering extended with agents_manifest, changelog_highlights, and runtime_config_snapshot; prompt text lookups added for new tools.
Agent/server callsites
src/api/agents.rs, src/main.rs, src/tools.rs
Call sites updated to pass agent.deps.runtime_config.clone() into cortex tool-server creation and adjust tool-server registrations to include new tools.
Release flow & changelog
scripts/release-tag.sh, .agents/skills/release-bump-changelog/SKILL.md, CHANGELOG.md
Release tagging script extended to resolve GitHub repo, accept/validate marketing copy, fetch GitHub release notes, upsert CHANGELOG.md; adds SKILL.md documentation and a populated CHANGELOG.md.
Docs & prompts updates
AGENTS.md, docs/content/docs/(core)/cortex.mdx, docs/content/docs/(deployment)/roadmap.mdx, docs/content/docs/(features)/tools.mdx, prompts/en/*.j2
Documentation and template prompts updated to document new tools (spacebot_docs, config_inspect), interactive Cortex chat changes, expanded tool inventories (task_* modules, memory_delete), and usage guidance.
Tool-server/task modules referenced
src/tools.rs, src/tools/*, AGENTS.md
Module entries and re-exports added for new tools; AGENTS.md updated to reference new task_* modules and memory_delete capability for branch ToolServer.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main changes: adding self-awareness documentation capabilities and runtime configuration diagnostic tools to the cortex system.
Description check ✅ Passed The description is well-structured and directly related to the changeset, covering all major components: the self_awareness module, new tools, prompt updates, release workflow changes, and validation steps.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch self-awareness

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Co-authored-by: tembo[bot] <208362400+tembo[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/tools/config_inspect.rs (1)

96-118: Consider consistent handling for missing vs unknown sections.

Lines 101-112 return Value::Null for binary_version, deployment, and mcp when the key doesn't exist, but lines 113-116 return an error for unknown sections. This creates an inconsistency: if someone requests "binary_version" and it's missing, they get null, but if they request an invalid key like "foo", they get an error.

If the intent is that binary_version/deployment/mcp are always present in the snapshot, the unwrap_or(Null) is defensive and fine. However, if a user typos "binary_versoin", they'll get a helpful error, whereas a typo on a valid key that happens to be absent silently returns null.

This is minor since the keys being special-cased should always exist in runtime_snapshot_value.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/tools/config_inspect.rs` around lines 96 - 118, select_section currently
returns serde_json::Value::Null for missing special-case keys ("binary_version",
"deployment", "mcp") but returns an error for other missing keys; make the
behavior consistent by returning an error when any requested key is missing. In
select_section, replace the .get(...).cloned().unwrap_or(Null) branches for
"binary_version", "deployment", and "mcp" with the same pattern used in the
default arm (i.e., .get(...).cloned().ok_or_else(||
unknown_section_error(section_or_key))), so missing special keys produce the
unknown_section_error; keep unknown_section_error as the canonical error helper.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.agents/skills/release-bump-changelog/SKILL.md:
- Around line 32-35: Rename the duplicate "3." list item to "4." in the SKILL.md
step labeled "Verify results" so the sequence flows correctly; locate the block
containing the commands (`git show --name-only --stat`, `git tag --list "v*"
--sort=-v:refname | head -n 5`) and update the leading number for that bullet
from 3. to 4. to fix the numbering inconsistency.

In `@CHANGELOG.md`:
- Around line 350-358: Remove the duplicated "What's Changed" and "New
Contributors" blocks for v0.1.5 (the repeated sections under "## What's Changed"
and "## New Contributors" that appear twice) so only one set of those entries
for v0.1.5 remains; locate the duplicate block that repeats the v0.1.5 entries
(the lines duplicating the bullet points for fixes and first-time contributors
and the "Full Changelog" link) and delete the redundant copy, leaving the
original v0.1.5 section intact.

In `@scripts/release-tag.sh`:
- Around line 226-231: The working-tree disallowed-changes check currently
exempts CARGO_TOML_RELATIVE, CARGO_LOCK_RELATIVE and
marketing_copy_allowed_relative but omits the changelog; update the conditional
that populates disallowed_changes (the if that compares "$file" to
"$CARGO_TOML_RELATIVE", "$CARGO_LOCK_RELATIVE", and
"$marketing_copy_allowed_relative") to also skip when "$file" equals
"$CHANGELOG_RELATIVE" so uncommitted CHANGELOG.md changes are treated as
allowed; ensure you reference the same variable names (file,
CARGO_TOML_RELATIVE, CARGO_LOCK_RELATIVE, marketing_copy_allowed_relative,
CHANGELOG_RELATIVE) and append no-op behavior to disallowed_changes when
matched.

---

Nitpick comments:
In `@src/tools/config_inspect.rs`:
- Around line 96-118: select_section currently returns serde_json::Value::Null
for missing special-case keys ("binary_version", "deployment", "mcp") but
returns an error for other missing keys; make the behavior consistent by
returning an error when any requested key is missing. In select_section, replace
the .get(...).cloned().unwrap_or(Null) branches for "binary_version",
"deployment", and "mcp" with the same pattern used in the default arm (i.e.,
.get(...).cloned().ok_or_else(|| unknown_section_error(section_or_key))), so
missing special keys produce the unknown_section_error; keep
unknown_section_error as the canonical error helper.

ℹ️ Review info
Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fcc69ba1-b151-4e4f-9b9c-6d839129347d

📥 Commits

Reviewing files that changed from the base of the PR and between 25a9bef and 6d7d68d.

📒 Files selected for processing (21)
  • .agents/skills/release-bump-changelog/SKILL.md
  • AGENTS.md
  • CHANGELOG.md
  • docs/content/docs/(core)/cortex.mdx
  • docs/content/docs/(deployment)/roadmap.mdx
  • docs/content/docs/(features)/tools.mdx
  • prompts/en/branch.md.j2
  • prompts/en/cortex_chat.md.j2
  • prompts/en/tools/config_inspect_description.md.j2
  • prompts/en/tools/spacebot_docs_description.md.j2
  • scripts/release-tag.sh
  • src/agent/cortex_chat.rs
  • src/api/agents.rs
  • src/lib.rs
  • src/main.rs
  • src/prompts/engine.rs
  • src/prompts/text.rs
  • src/self_awareness.rs
  • src/tools.rs
  • src/tools/config_inspect.rs
  • src/tools/spacebot_docs.rs

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/self_awareness.rs (1)

84-101: ⚠️ Potential issue | 🟠 Major

Redact MCP transport fields in runtime snapshots to prevent secret exposure.

Line 90 currently emits raw args, and Line 99 emits raw url; both can contain credentials/tokens and may leak through diagnostics and prompts.

💡 Proposed fix
                 McpTransport::Stdio { command, args, env } => {
                     let mut env_keys = env.keys().cloned().collect::<Vec<_>>();
                     env_keys.sort();
                     json!({
                         "kind": "stdio",
                         "command": command,
-                        "args": args,
+                        "args_count": args.len(),
                         "env_keys": env_keys,
                     })
                 }
                 McpTransport::Http { url, headers } => {
                     let mut header_keys = headers.keys().cloned().collect::<Vec<_>>();
                     header_keys.sort();
                     json!({
                         "kind": "http",
-                        "url": url,
+                        "url_redacted": true,
                         "header_keys": header_keys,
                     })
                 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/self_awareness.rs` around lines 84 - 101, The snapshot currently emits
raw transport fields that may contain secrets: in McpTransport::Stdio do not
include the raw args vector (variable args) in the json, and in
McpTransport::Http do not include the raw url (variable url); instead replace
them with a redacted placeholder (e.g. "<redacted>") or a safe summary (e.g.
args_count and url_present boolean) while still preserving command, env_keys and
header_keys for diagnostics; update the McpTransport::Stdio and
McpTransport::Http match arms to output the redacted/summarized fields rather
than the raw args and url.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/self_awareness.rs`:
- Around line 46-56: Remove the duplicated function declaration and stray brace:
keep a single pub fn changelog_highlights() -> String implementation that calls
latest_release_notes(CHANGELOG_DOC, 3).unwrap_or_else(...) and delete the extra
duplicated signature and the extra closing brace so the function block is
properly formed; ensure the final function contains the fallback using
CHANGELOG_DOC.lines().take(200).collect::<Vec<_>>().join("\n") and compiles
cleanly.

---

Duplicate comments:
In `@src/self_awareness.rs`:
- Around line 84-101: The snapshot currently emits raw transport fields that may
contain secrets: in McpTransport::Stdio do not include the raw args vector
(variable args) in the json, and in McpTransport::Http do not include the raw
url (variable url); instead replace them with a redacted placeholder (e.g.
"<redacted>") or a safe summary (e.g. args_count and url_present boolean) while
still preserving command, env_keys and header_keys for diagnostics; update the
McpTransport::Stdio and McpTransport::Http match arms to output the
redacted/summarized fields rather than the raw args and url.

ℹ️ Review info
Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ce132cf1-e140-4ed1-944f-65357c77ffac

📥 Commits

Reviewing files that changed from the base of the PR and between 6d7d68d and f7384c8.

📒 Files selected for processing (1)
  • src/self_awareness.rs

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
CHANGELOG.md (1)

61-63: Make the v0.2.0 narrative a subheading, not a release heading.

Line 61 currently looks version-heading-like at ## level. Using a subheading (###) keeps release boundaries unambiguous for humans and release tooling.

✏️ Suggested change
-## v0.2.0 is the _biggest_ Spacebot release yet. 
+### Release Story
+
+v0.2.0 is the _biggest_ Spacebot release yet.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CHANGELOG.md` around lines 61 - 63, The release line "## v0.2.0 is the
_biggest_ Spacebot release yet." should be demoted from an H2 to an H3 to make
it a subheading; update the Markdown heading marker from "##" to "###" for that
exact line so the v0.2.0 narrative becomes a subheading and keeps release
boundary headings unambiguous.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/tools/spacebot_docs.rs`:
- Around line 171-194: The handler currently computes start_line from
args.start_line and calls slice_lines(...) then builds a success
SpacebotDocsOutput which can report inverted or out-of-range ranges if
args.start_line is past EOF; update the logic around args.start_line,
args.max_lines and the return path in the code that constructs
SpacebotDocsOutput/SpacebotDocContent so that you first call
slice_lines(&document.content, start_line, max_lines) to get total_lines, then
if start_line > total_lines either return a structured error result (success:
false with a clear message) or normalize values (set start_line = total_lines,
end_line = total_lines, has_more = false, content = empty) before creating
SpacebotDocsOutput; reference slice_lines, SpacebotDocsOutput,
SpacebotDocContent, args.start_line and args.max_lines when making the change.

---

Nitpick comments:
In `@CHANGELOG.md`:
- Around line 61-63: The release line "## v0.2.0 is the _biggest_ Spacebot
release yet." should be demoted from an H2 to an H3 to make it a subheading;
update the Markdown heading marker from "##" to "###" for that exact line so the
v0.2.0 narrative becomes a subheading and keeps release boundary headings
unambiguous.

ℹ️ Review info
Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 98b79fbf-99a7-44fc-8ac1-1410d208723c

📥 Commits

Reviewing files that changed from the base of the PR and between f7384c8 and 11e8e6d.

📒 Files selected for processing (7)
  • .agents/skills/release-bump-changelog/SKILL.md
  • CHANGELOG.md
  • scripts/release-tag.sh
  • src/agent/cortex_chat.rs
  • src/self_awareness.rs
  • src/tools/config_inspect.rs
  • src/tools/spacebot_docs.rs

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/tools/spacebot_docs.rs`:
- Around line 155-170: The read branch currently returns Err on user/LLM
mistakes (missing doc_id via requested_id and missing document from
crate::self_awareness::get_embedded_doc leading to unknown_doc_error) — change
these to return a structured tool response (Ok with a payload like { success:
false, error: "<message>" }) so failures are recoverable by the model rather
than bubbling as Err; do the same for the invalid-action path referenced around
the 208-210 checks (return Ok structured failure for unrecognized actions) and
ensure the caller still receives the same success:true/false schema expected by
the tool contract.
- Around line 135-150: The message uses docs.len() after truncation so when
results were trimmed to 200 it incorrectly reports "200 docs available"; before
truncating (in the function that builds SpacebotDocsOutput) capture the total
count (e.g., let total = docs.len()), then truncate docs to 200 and use total
for the availability message while optionally indicating the shown count (e.g.,
format!("{} docs available (showing {})", total, docs.len())); update the
formatted message building code that references args.query to combine the
total/shown counts and the query filter text accordingly.

ℹ️ Review info
Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 22a2d954-742e-481e-b2cd-78b93a8301d6

📥 Commits

Reviewing files that changed from the base of the PR and between 11e8e6d and c3921a1.

📒 Files selected for processing (3)
  • prompts/en/channel.md.j2
  • prompts/en/tools/branch_description.md.j2
  • src/tools/spacebot_docs.rs

Comment on lines +135 to +150
if docs.len() > 200 {
docs.truncate(200);
}

Ok(SpacebotDocsOutput {
success: true,
action,
message: format!(
"{} docs available{}",
docs.len(),
args.query
.as_deref()
.filter(|query| !query.trim().is_empty())
.map(|query| format!(" (filtered by '{query}')"))
.unwrap_or_default()
),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

List message becomes inaccurate after truncation.

When results exceed 200, the output says “200 docs available” even if more exist. This can mislead downstream tool selection.

Suggested fix
             "list" => {
-                let mut docs = crate::self_awareness::list_embedded_docs(args.query.as_deref());
-                if docs.len() > 200 {
+                let mut docs = crate::self_awareness::list_embedded_docs(args.query.as_deref());
+                let total_matches = docs.len();
+                if total_matches > 200 {
                     docs.truncate(200);
                 }
@@
-                    message: format!(
-                        "{} docs available{}",
-                        docs.len(),
+                    message: format!(
+                        "{} docs returned{}{}",
+                        docs.len(),
+                        if total_matches > docs.len() {
+                            format!(" (truncated from {total_matches})")
+                        } else {
+                            String::new()
+                        },
                         args.query
                             .as_deref()
                             .filter(|query| !query.trim().is_empty())
                             .map(|query| format!(" (filtered by '{query}')"))
                             .unwrap_or_default()
                     ),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/tools/spacebot_docs.rs` around lines 135 - 150, The message uses
docs.len() after truncation so when results were trimmed to 200 it incorrectly
reports "200 docs available"; before truncating (in the function that builds
SpacebotDocsOutput) capture the total count (e.g., let total = docs.len()), then
truncate docs to 200 and use total for the availability message while optionally
indicating the shown count (e.g., format!("{} docs available (showing {})",
total, docs.len())); update the formatted message building code that references
args.query to combine the total/shown counts and the query filter text
accordingly.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/tools/spacebot_docs.rs (1)

135-151: ⚠️ Potential issue | 🟡 Minor

List response message is inaccurate when results are truncated.

After truncating to 200 (Line 136-Line 138), the message still reports docs.len() as “docs available,” which hides that more matches may exist.

Suggested fix
             "list" => {
                 let mut docs = crate::self_awareness::list_embedded_docs(args.query.as_deref());
-                if docs.len() > 200 {
+                let total_matches = docs.len();
+                if total_matches > 200 {
                     docs.truncate(200);
                 }

                 Ok(SpacebotDocsOutput {
                     success: true,
                     action,
                     message: format!(
-                        "{} docs available{}",
+                        "{} docs returned{}{}",
                         docs.len(),
+                        if total_matches > docs.len() {
+                            format!(" (truncated from {total_matches})")
+                        } else {
+                            String::new()
+                        },
                         args.query
                             .as_deref()
                             .filter(|query| !query.trim().is_empty())
                             .map(|query| format!(" (filtered by '{query}')"))
                             .unwrap_or_default()
                     ),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/tools/spacebot_docs.rs` around lines 135 - 151, The message wrongly
reports docs.len() after truncation; capture the full match count before
truncating (e.g., let total = docs.len()) right after calling
crate::self_awareness::list_embedded_docs, then truncate docs to 200 and build
SpacebotDocsOutput.message using both values (e.g., format!("showing {} of {}
docs available{}", docs.len(), total, ...)) so the output clearly indicates when
results are truncated; update the code around list_embedded_docs, docs
truncation, and the SpacebotDocsOutput construction to use these variables.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/tools/spacebot_docs.rs`:
- Around line 135-151: The message wrongly reports docs.len() after truncation;
capture the full match count before truncating (e.g., let total = docs.len())
right after calling crate::self_awareness::list_embedded_docs, then truncate
docs to 200 and build SpacebotDocsOutput.message using both values (e.g.,
format!("showing {} of {} docs available{}", docs.len(), total, ...)) so the
output clearly indicates when results are truncated; update the code around
list_embedded_docs, docs truncation, and the SpacebotDocsOutput construction to
use these variables.

ℹ️ Review info
Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cb7f9670-4f74-4f86-a174-466c04e11c9e

📥 Commits

Reviewing files that changed from the base of the PR and between c3921a1 and cb020f0.

📒 Files selected for processing (1)
  • src/tools/spacebot_docs.rs

@jamiepine jamiepine merged commit 23929f9 into main Mar 4, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant