feat(api): describe_feature tool (chat + MCP) - #183
Conversation
Add a read-only describe_feature tool to both agent surfaces so the assistant can explain Orbit mechanics (streaks, freezes, frequencies, gamification, notifications, paygate, schedule-math, ai-memory) from the pre-authored markdown bundle instead of carrying that prose in the system prompt. - New shared IFeatureExplanationService loads and parses the already embedded 8-file FeatureExplanations bundle (hand-rolled frontmatter parse, no YAML dependency); both surfaces resolve the same singleton. - Chat DescribeFeatureTool : IAiTool (IsReadOnly) returns the markdown body plus display_name / related_capabilities / related_surfaces. - MCP FeatureTools [McpServerTool] calls the service directly (pure read, not via McpExecutorBridge). - New DescribeFeature catalog capability (Low risk, no confirmation, reuses catalog_read scope) maps describe_feature in chatTools + mcpTools. - Additive system-prompt pointer as rule 19 in GlobalRulesSection. - Tests: enum<->file three-way agreement, tool behavior/metadata, and drift tests pinning AppConstants + LevelDefinitions XP table to the markdown. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Solid addition. The IFeatureExplanationService singleton parses the embedded bundle once at startup and exposes it correctly to both surfaces (chat IAiTool and MCP [McpServerTool]). Frontmatter parser handles CRLF normalization, missing fields, and unterminated fences correctly. Service registration order is right — singleton injected into scoped DescribeFeatureTool is fine. The ClaimsPrincipal user parameter in FeatureTools follows the established MCP injection pattern across the codebase. isPhaseOneReadOnly: false is consistent with the entire existing catalog. Test coverage is thorough: three-way enum/file/service agreement, tool metadata, success/error paths, and the drift tests that pin AppConstants and LevelDefinitions to the markdown prose are a nice safeguard.
# Conflicts: # src/Orbit.Api/Extensions/ServiceCollectionExtensions.cs
There was a problem hiding this comment.
The merge commit only resolves a conflict in ServiceCollectionExtensions.cs — all three DI registrations (AddScoped<IAiTool, DescribeFeatureTool>, AddSingleton<IFeatureExplanationService, FeatureExplanationService>, .WithTools<FeatureTools>()) are preserved correctly. No new logic introduced since the previous approval. Still solid.
…ing (#261) * feat(gamification): free-tier rebalance + infinite levels + recap (#186, #190) Reversible gamification_free_tier AppFeatureFlag (default off) unlocks streak/XP/level + streak-freeze auto-activation for free users. Infinite levels via 100*L^2 curve, continuous past level 10. New half_year_hero/streak_titan achievements + reserved first_cheer. GET /api/gamification/recap returns metrics-only retrospective + referral shareDeepLink, ungated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(astra): warm persona tone + soften act-immediately framing (#183) New EncouragingToneSection (Order 150) + softened CoreIdentitySection so clarify-first coexists with direct action; destructive/bulk route through existing confirmation-card gating. Reuses shipped resolve + pendingOperations infra; gpt-4.1-mini unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(social): social foundation - friendships, cheers, feed, moderation, handles (#193) 5 entities + User.Handle/SocialOptIn + migration w/ deterministic handle backfill. Endpoints (request/accept/remove/list/feed/cheer/block/report + set-handle + opt-in), SocialAccessGuard, rate limits. OpenAI moderation (fail-open on outage). FriendFeedEvent write-pipeline: streak hook (all users) + achievement hook (Pro) + keyset read. first_cheer wired; FCM pushes; export + deletion purge. Backend + shared only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(onboarding): setup-checklist flags, bulk-create tags, template-pack support (#187, #189) User onboarding-checklist completion flags (ride profile payload, auto-set from signals) + onboarding achievement hook (#189). BulkCreateHabits accepts per-item tags resolved/created by name for starter packs (#187). Migration AddOnboardingChecklistFlags. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(api): address PR #261 review — block-filter cheers, unblock validator, feed leak, period 400 (#193, #190) Resolves claude-review findings: add UnblockUserCommandValidator (HIGH); filter blocked users from GetCheersQuery both directions (HIGH); drop opted-out actors from the friend feed (MED); MaximumLength on friend-request handle/referralCode (MED); recap period set now matches the resolver via a shared IsKnownPeriod (single source of truth) + an invalid period returns 400 not 500 at the recap/retrospective endpoints (MED). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(api): #261 round-2 review — block/unblock rate limits, GetFriends validator, ordering, cheer-ownership Rate-limit block/unblock (50/24h); add GetFriendsQueryValidator (UserId NotEmpty); check target existence before BlockedUser.Create; verify a reported CheerId involves the reported user (else CheerNotFound). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Adds a read-only
describe_featuretool to Orbit AI's dual agent surface (chatIAiTool+ MCP[McpServerTool]). The tool returns the pre-authored markdown explanation for one of 8 feature keys plus its metadata (display_name,related_capabilities,related_surfaces), so the assistant can explain app mechanics on demand instead of carrying that prose in the system prompt.The content bundle was already embedded; this PR wires it into the agent surfaces.
Changes
IFeatureExplanationService/FeatureExplanationServiceinOrbit.Applicationloads + parses the embedded 8-fileFeatureExplanationsbundle once (hand-rolled frontmatter parser, no YAML dependency). Registered as a singleton; both surfaces resolve the same instance.DescribeFeatureTool : IAiTool(IsReadOnly = true) with a requiredfeature_keyenum mirroring the 8 keys; returns markdown body + metadata payload.FeatureTools.DescribeFeature[McpServerTool]calls the service directly — pure read, not routed throughMcpExecutorBridge(per the read-tool routing rule). Registered via.WithTools<FeatureTools>().AgentCapabilityIds.DescribeFeaturecapability (Low risk,AgentConfirmationRequirement.None,catalogdomain, reuses the existingcatalog_readscope) mapsdescribe_featurein bothchatToolsandmcpTools.GlobalRulesSection.cstelling the model to calldescribe_featurefor mechanic questions. Net-additive — rules 1-18 unchanged; no trim.AppConstantsfreeze/lookback/paygate/user-fact/overdue constants and the fullLevelDefinitionsXP table to the markdown. Confirmed the drift test fails when a constant is bumped, then reverted.Validation
dotnet build Orbit.slnx— 0 errors (pre-existing NU1902/MSB3277/CS8602 warnings only).Orbit.Application.Tests— 1718 passed, 0 failed.Orbit.Infrastructure.Tests— 932 passed, 0 failed (incl.AgentCatalogServiceTestsmapping guardrails +GlobalRulesSectionpointer assertion).Orbit.Domain.Tests— 344 passed, 0 failed.Refs thomasluizon/orbit-ui-mobile#90
🤖 Generated with Claude Code