diff --git a/.github/ISSUE_TEMPLATE/cookbook-recipe.yml b/.github/ISSUE_TEMPLATE/cookbook-recipe.yml new file mode 100644 index 000000000..8f12a7dba --- /dev/null +++ b/.github/ISSUE_TEMPLATE/cookbook-recipe.yml @@ -0,0 +1,103 @@ +name: Cookbook recipe +description: Propose a reusable Roomote workflow for the public Cookbook. +title: "[Cookbook]: " +labels: ["documentation", "needs-triage"] +body: + - type: markdown + attributes: + value: | + Use this form to propose a complete, reusable Roomote workflow for the Cookbook. + Start with the [contributing recipes guide](https://docs.roomote.dev/cookbook/template), + paste the completed recipe below, and keep credentials, customer data, and + private operational details out of the example. + - type: checkboxes + id: preflight + attributes: + label: Preflight + options: + - label: I searched the existing Cookbook and docs for a duplicate or closely related recipe. + required: true + - label: I removed secrets, tokens, private keys, customer data, and private repository details. + required: true + - label: I stated provider support, permission boundaries, and other limitations plainly. + required: true + - type: textarea + id: recipe + attributes: + label: Recipe + description: Paste the completed Markdown recipe from the contributing recipes guide. + placeholder: | + --- + title: Outcome-first recipe title + description: One sentence explaining the finished system and why it matters. + icon: lucide-icon-name + contributor: Name or team + contributor_url: https://example.com/contributor + contributor_company: Company + contributor_company_url: https://example.com/company + --- + + ## Overview + + Explain the recurring problem and the outcome this recipe creates. + + - **Trigger**: Trigger type + - **Setup time**: About N minutes + - **Requires**: Product access, integrations, permissions + - **Serves**: Teams or roles + - **Cooked By**: Name or team from Company + + ## Ingredients + + - Ingredient + + ## Steps + + 1. First step. + + ## Paste-ready configuration + + ```text + Configuration or prompt + ``` + + ## Variations + + - Variation + validations: + required: true + - type: textarea + id: validation + attributes: + label: Validation and limitations + description: Explain what you tested, which providers or integrations it requires, and any known limitations. + validations: + required: true + - type: input + id: contributor + attributes: + label: Contributor + description: Name the person or team contributing this recipe. + validations: + required: true + - type: input + id: contributor_url + attributes: + label: Contributor URL + description: Link to the contributor's public profile or website, if available. + validations: + required: false + - type: input + id: contributor_company + attributes: + label: Contributor company + description: Name of the contributor's company, if applicable. + validations: + required: false + - type: input + id: contributor_company_url + attributes: + label: Contributor company URL + description: Link to the contributor's company website, if available. + validations: + required: false diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..d568c003e --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,44 @@ +name: Docs + +on: + push: + branches: [main, develop] + paths: + - "apps/docs/**" + - "pnpm-lock.yaml" + - "pnpm-workspace.yaml" + - ".github/actions/setup-environment/**" + - ".github/workflows/docs.yml" + pull_request: + branches: [main, develop] + paths: + - "apps/docs/**" + - "pnpm-lock.yaml" + - "pnpm-workspace.yaml" + - ".github/actions/setup-environment/**" + - ".github/workflows/docs.yml" + +permissions: + contents: read + +env: + NODE_VERSION: 24.13.1 + PNPM_VERSION: 10.29.3 + +jobs: + docs: + name: Validate docs + runs-on: blacksmith-4vcpu-ubuntu-2404 + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - name: Setup environment + uses: ./.github/actions/setup-environment + with: + frozen-lockfile: 'true' + node-version: ${{ env.NODE_VERSION }} + pnpm-version: ${{ env.PNPM_VERSION }} + - name: Check generated Cookbook index + run: pnpm --filter @roomote/docs check-cookbook-index + - name: Validate docs and links + run: pnpm --filter @roomote/docs check diff --git a/apps/docs/README.md b/apps/docs/README.md index dcaaea11e..b7098508c 100644 --- a/apps/docs/README.md +++ b/apps/docs/README.md @@ -20,10 +20,10 @@ and assets all live in this directory and do not depend on `@roomote/web`. ## Local development -Install the Mintlify CLI (`mint`) globally, then run the dev server: +The docs scripts download a pinned Mintlify CLI automatically, so no global +install is required. Run the dev server with: ```bash -npm install -g mint pnpm --filter @roomote/docs dev ``` diff --git a/apps/docs/automations.mdx b/apps/docs/automations.mdx index 185bc476a..1dbb83c80 100644 --- a/apps/docs/automations.mdx +++ b/apps/docs/automations.mdx @@ -12,6 +12,10 @@ or a communications provider when an automation depends on those services. Automations are most useful when your team already trusts the normal task review flow and wants Roomote to keep an eye on repeated work. + + Unsure of how Automations can help? Get inspiration from the [Cookbook](/cookbook). + + ## Before you turn them on Make sure the basics are in place: @@ -93,6 +97,11 @@ automation to test it immediately. The deployment cap is 25 custom automations. +See [Schedule maintenance](/cookbook/scheduled-housekeeping) +for three copyable custom automation prompts, or +[draft a product-updates newsletter](/cookbook/product-updates-newsletter) with +a custom MCP server and a natural-language schedule. + The **Scheduling timezone** setting is available on both the Automations and Deployment settings pages. It applies to all scheduled automations and to natural-language schedule interpretation. Existing deployments continue using @@ -136,6 +145,10 @@ Start with a low-risk channel first. Auto-response can feel noisy if the channel mixes casual discussion with requests that should become Roomote tasks. +See how channel instructions and launch criteria work together in the +[vendor outage triage](/cookbook/vendor-outage-triage) and +[support channel](/cookbook/support-channel) recipes. + ## Manager automations The manager section controls the shared Manager Channel plus recurring @@ -228,6 +241,9 @@ For Gitea, repository webhook resync includes the `workflow_run` event so Actions completions reach Roomote; host matching uses the deployment `GITEA_BASE_URL`. +Follow the [CI failure auto-fix recipe](/cookbook/ci-failure-auto-fix) for a +copyable noise-control configuration. + ## Add instructions to reduce noise Several automations include an **Additional instructions** field. Use it to diff --git a/apps/docs/cookbook/ci-failure-auto-fix.mdx b/apps/docs/cookbook/ci-failure-auto-fix.mdx new file mode 100644 index 000000000..93c459e67 --- /dev/null +++ b/apps/docs/cookbook/ci-failure-auto-fix.mdx @@ -0,0 +1,49 @@ +--- +title: Fix CI failures +description: Keep the build green by having Roomote verify and fix CI breakages automatically. +contributor: Matt Rubens +contributor_url: https://github.com/mrubens +contributor_company: Roomote +contributor_company_url: https://roomote.dev +--- + +## Overview + +When CI fails on your default branch, Roomote reacts immediately. It checks +that the failure is real, reproduces the failing job inside the repository's +environment, finds the root cause, opens a PR with the fix, and posts one +summary to the Manager Channel. The team finds a green PR waiting instead of a +red branch. This is a built-in automation, so the recipe is one toggle plus +clear instructions. + +- **Trigger**: Webhook +- **Setup time**: About 10 minutes +- **Requires**: Admin access, source control, Manager Channel +- **Serves**: Engineers +- **Cooked By**: [Matt Rubens](https://github.com/mrubens) from [Roomote](https://roomote.dev) + +## Ingredients + +- [CI Failure Triage](/automations#manager-automations) +- A Manager Channel destination configured under **Automation output** +- An environment for every repository you want triaged. Repositories outside an environment are skipped. + +## Steps + +1. Set the Manager Channel under **Settings > Automations > Automation output**. +2. Enable **CI Failure Triage**. +3. Confirm each repository you care about belongs to a configured environment. +5. Use **Run now** to test the configuration, or wait for the next default-branch failure. + +## Variations + +- Keep experimental repositories out of environments to exclude them from triage. +- Route the summary to a dedicated `#ci-triage` channel instead of the shared Manager Channel. + +CI Failure Triage reacts only to failures on the default branch. It supports +GitHub Actions, GitLab Pipelines, Azure DevOps builds, Bitbucket Pipelines, and +Gitea Actions. GitLab requires Pipeline Hooks on the webhook, and Bitbucket +requires the Pipelines OAuth scope. + +**Pairs well with:** [scheduled housekeeping](/cookbook/scheduled-housekeeping) · +[vendor outage triage](/cookbook/vendor-outage-triage) diff --git a/apps/docs/cookbook/index.mdx b/apps/docs/cookbook/index.mdx new file mode 100644 index 000000000..d2172a276 --- /dev/null +++ b/apps/docs/cookbook/index.mdx @@ -0,0 +1,27 @@ +--- +title: Cookbook +icon: cooking-pot +description: Copyable recipes for turning Roomote automations, skills, and integrations into standing team systems. +--- + +Roomote's abilities go way beyond ad hoc prompt → PR interactions. With integrations and automations, you can put many of your team's workflows on autopilot, from investigation to resolution and beyond. + +This cookbook collects proven recipes to help you boost your team's productivity +and the quality of your output. + +{/* cookbook-recipes:start */} +| Recipe | Use to | +| --- | --- | +| [Draft product updates](/cookbook/product-updates-newsletter) | Turn recent product work into a customer-ready draft | +| [Evaluate outage impact](/cookbook/vendor-outage-triage) | Filter vendor status noise by comparing each incident with your real code, regions, and feature usage. | +| [Fix CI failures](/cookbook/ci-failure-auto-fix) | Keep the build green by having Roomote verify and fix CI breakages automatically. | +| [Schedule maintenance](/cookbook/scheduled-housekeeping) | Turn flaky-test scans, feature-flag audits, and dependency reviews into recurring Roomote work. | +| [Triage customer issues](/cookbook/support-channel) | Give support escalations a repeatable path through production evidence, data, and code. | +{/* cookbook-recipes:end */} + +## Contribute a recipe + +Have a Roomote workflow other teams could reuse? Start with +[contributing recipes](/cookbook/template), fill in every section, and open a +[Cookbook recipe issue](https://github.com/RooCodeInc/Roomote/issues/new?template=cookbook-recipe.yml) +on the Roomote repository. diff --git a/apps/docs/cookbook/product-updates-newsletter.mdx b/apps/docs/cookbook/product-updates-newsletter.mdx new file mode 100644 index 000000000..982015f05 --- /dev/null +++ b/apps/docs/cookbook/product-updates-newsletter.mdx @@ -0,0 +1,73 @@ +--- +title: Draft product updates +description: Turn recent product work into a customer-ready draft +contributor: Bruno Bergher +contributor_url: https://github.com/brunobergher +contributor_company: Roomote +contributor_company_url: https://roomote.dev +--- + +## Overview + +Product-update emails are chronically late because someone has to remember what +shipped, translate commit-speak into customer language, and then fight the +email tool. This automation does all three: every week it reads merged PRs +across your product repositories, writes the newsletter, and creates a draft in +Resend through a custom MCP server, ready for review. + +It's how we actually generate the ones we send every Friday. + +- **Trigger**: Schedule +- **Setup time**: About 30 minutes +- **Requires**: Admin access, custom Resend MCP server +- **Serves**: PMs, Founders, Marketing +- **Cooked By**: [Bruno Bergher](https://github.com/brunobergher) from [Roomote](https://roomote.dev) + +## Ingredients + +- A [custom automation](/automations#custom-automations) +- An environment covering the product repositories +- The Resend MCP server configured under **Settings > Integrations**, with a Resend API key +- A report destination such as `#product-updates`, so the draft lands in a replyable thread + +## Steps + +1. Add the Resend MCP server and confirm its tools are available in the environment. +2. Create a custom automation named **Product Updates Newsletter**. Choose **Custom schedule**, enter `Mondays at 9am`, and select the environment. +3. Paste the prompt below. +4. Set the report destination to `#product-updates`. +5. Use **Run now** to generate the first draft, then calibrate its tone by replying in the thread. + +## Automation prompt + +```text +Write this week's product-updates newsletter. + +1. Collect the PRs merged to the default branch in the last 7 days across the + product repositories. +2. Keep only customer-visible changes: features, improvements, and fixes a + user would notice. Skip refactors, internal tooling, and dependency bumps. +3. Write the newsletter: + - a one-line subject + - a two-sentence introduction + - one short section per change: what is new, why it matters, how to try it + Use plain language. Do not include ticket numbers or internal codenames. +4. Using the Resend MCP server, create a DRAFT broadcast with this content for + the "Product updates" audience. Do not send it. +5. Post the draft content and the Resend draft link in this thread for review. + +If nothing customer-visible shipped this week, say so in the thread and skip +the draft. Do not pad the newsletter. +``` + +## Variations + +- Without Resend, remove step 4 and post ready-to-paste Markdown for any email tool. +- Run monthly with `first Monday of the month at 9am`. +- Use separate automations for customer notes and a technical internal changelog. + +This recipe showcases custom MCP servers, natural-language scheduling, and +replyable automation threads. Review the draft before sending it; the automation +is deliberately instructed to create a draft, not send a broadcast. + +**Pairs well with:** [scheduled housekeeping](/cookbook/scheduled-housekeeping) diff --git a/apps/docs/cookbook/scheduled-housekeeping.mdx b/apps/docs/cookbook/scheduled-housekeeping.mdx new file mode 100644 index 000000000..ba7d5f47e --- /dev/null +++ b/apps/docs/cookbook/scheduled-housekeeping.mdx @@ -0,0 +1,83 @@ +--- +title: Schedule maintenance +description: Turn flaky-test scans, feature-flag audits, and dependency reviews into recurring Roomote work. +contributor: Bruno Bergher +contributor_url: https://github.com/brunobergher +contributor_company: Roomote +contributor_company_url: https://roomote.dev +--- + +## Overview + +Every team has maintenance work that only happens when someone feels guilty: +flaky tests, stale feature flags, and aging dependencies. A custom automation +turns each chore into a standing appointment: a prompt, a cadence, and a channel +where results land in a replyable thread. Once you have built one, you will +start spotting more work that fits the pattern. + +- **Trigger**: Schedule +- **Setup time**: About 15 minutes +- **Requires**: Admin access +- **Serves**: Engineers, Leads +- **Cooked By**: [Bruno Bergher](https://github.com/brunobergher) from [Roomote](https://roomote.dev) + + +## Ingredients + +- One [custom automation](/automations#custom-automations) per chore, within the deployment cap of 25 +- One environment per automation +- A report destination such as `#eng-maintenance` + +## Steps + +1. Under **Settings > Automations > Custom automations**, create an automation. +2. Pick a prompt below, choose a cadence, and select the environment. Natural-language schedules such as `weekdays at 9am` are supported under **Custom schedule**. +3. Set a report destination so results become a conversation rather than a log line. +4. Use **Run now** to check the first report, then let the schedule take over. +5. Reply in the thread to steer a run, for example `Open the PR for item 2`, without changing the automation. + +## Prompt: flaky tests + +Run weekly: + +```text +Find flaky tests. Look at recent CI runs for tests that failed and then passed +with no related code change. For each suspect, read the test and identify the +likely cause: timing, shared state, network, or ordering. Report the top 3 with +evidence. If one has an obvious, safe fix, open a PR for that one only. +``` + +## Prompt: stale feature flags + +Run weekly or monthly: + +```text +Audit feature flags. List every flag defined in the codebase. Flag the ones +that are fully rolled out and effectively always on, referenced nowhere, or +whose code paths are dead. Report which can be removed and what removing them +simplifies. Open a cleanup PR for at most one clearly dead flag per run. +``` + +## Prompt: dependency review + +Run weekly: + +```text +Review our dependencies for updates worth taking: security patches first, +then major versions of core frameworks. For each candidate, summarize what +changed upstream and the migration risk for our codebase specifically. Do not +open PRs. End with a ranked shortlist of updates worth scheduling this sprint. +``` + +## Variations + +- Create a Monday briefing that summarizes open PRs, stale branches, and work waiting on review. +- Compare `apps/docs` with customer-visible changes shipped in the last week and report documentation drift. +- Use a model override for heavyweight audits and the deployment default for cheaper checks. + +Custom automations also support five-field cron expressions, **Run now**, and +replyable result threads. Without a report destination, runs are silent and +their results appear only in the task view. + +**Pairs well with:** [CI failure auto-fix](/cookbook/ci-failure-auto-fix) · +[product-updates newsletter](/cookbook/product-updates-newsletter) diff --git a/apps/docs/cookbook/support-channel.mdx b/apps/docs/cookbook/support-channel.mdx new file mode 100644 index 000000000..9dcf8d3ac --- /dev/null +++ b/apps/docs/cookbook/support-channel.mdx @@ -0,0 +1,111 @@ +--- +title: Triage customer issues +description: Give support escalations a repeatable path through production evidence, data, and code. +contributor: John Stearns +contributor_company: Roo Vet +contributor_company_url: https://roo.vet +--- + +## Overview + +Customer-facing teams post escalations into an operations channel, often from a +ticketing system. A custom skill teaches Roomote your triage procedure: check +logs, inspect data, read code, and classify the problem as a product bug, a +data-state issue, or expected behavior. Roomote answers in the thread with +evidence, and a PR when the resolution is a code fix. Engineers only see what +survives triage. + +- **Trigger**: Channel event +- **Setup time**: About 45 minutes +- **Requires**: Admin access, Slack or Discord, observability or data integration +- **Serves**: Support, Engineers +- **Cooked By**: John Stearns from [Roo Vet](https://roo.vet) + +## Ingredients + +- A channel receiving support escalations, such as `#support-inbound`, with Roomote invited +- [Auto-respond channels](/automations#channel-automations), or a ticketing workflow that mentions Roomote +- A [custom skill](/skills#when-to-use-a-custom-skill), enabled for the product environment +- Observability and data integrations such as [Sentry](/integrations/sentry), [Grafana](/integrations/grafana), [Better Stack](/integrations/better-stack), [Supabase](/integrations/supabase), [Neon](/integrations/neon), or [Snowflake](/integrations/snowflake), or a custom MCP server for your stack +- An environment for the product repositories, with read-only production credentials where integrations do not cover the required system + +## Steps + +1. Connect the integrations your triage needs under **Settings > Integrations**. +2. Under **Settings > Skills**, add the custom skill below and enable it for the environment your product runs in. +3. Add the escalation channel under **Settings > Automations > Auto-respond to channels** and paste the launch criteria. +4. Repost a resolved historical ticket and compare Roomote's triage with what actually happened. +5. Tighten the skill with what you learn. The skill is the control you will keep tuning. + +## Custom skill + +Create a custom skill with these field values. The Roomote UI stores the slug, +description, and content separately. + +**Slug** + +```text +support-investigation +``` + +**Description** + +```text +Use when a customer issue or support escalation needs triage: classify it as a +product bug, a data-state problem, or expected behavior, then resolve it or +prepare the escalation. +``` + +**Content** + +```markdown +When a support escalation arrives: + +1. Restate the problem: which customer, which feature, what they expected, + and what actually happened. +2. Check errors first: search Sentry for exceptions matching the feature and + time window. Note anything correlated. +3. Check the data: query the production database with read-only access to + inspect the customer's relevant records. Never write to production. +4. Read the code path involved, then classify: + - Product bug: implement the fix and open a PR; link it in the thread. + - Data-state problem: identify the exact records and describe the + corrective action for an operator. Do not modify data yourself. + - Expected behavior or user error: draft a reply the support agent can + send, citing the relevant docs. +5. Reply in the thread with the classification, evidence (queries run, error + links, and code references), and the PR, proposed data fix, or reply draft. + +Escalate to an engineer only when the fix needs a product decision or a +production data change. +``` + +## Launch criteria + +```text +Launch for messages describing a specific customer-reported problem or support +escalation, usually posted by the ticketing bot or a support teammate. + +Do not launch for general questions, internal discussion, status updates on +tickets already being worked, or messages that only link a ticket without +describing the problem. + +If an earlier message about the same ticket already launched, launch again +only if the customer reports the problem recurring after it was thought +resolved. +``` + +## Variations + +- Ask Roomote to propose, but not run, a data-repair script as a reviewed PR against an operations repository. +- Create separate skills by product area, each with a sharper description so the right one activates. +- On Teams, have the ticketing workflow mention Roomote and name `support-investigation`; auto-respond is not available there today. + +This recipe is most valuable with real log and read-only database access. Grant +scoped, read-only credentials through integrations or environment variables. +The skill says never to write to production; admins should also enforce the +boundary with database roles and MCP tool policies. A prompt is not a security +boundary. + +**Pairs well with:** [vendor outage triage](/cookbook/vendor-outage-triage) · +[CI failure auto-fix](/cookbook/ci-failure-auto-fix) diff --git a/apps/docs/cookbook/template.mdx b/apps/docs/cookbook/template.mdx new file mode 100644 index 000000000..111564f89 --- /dev/null +++ b/apps/docs/cookbook/template.mdx @@ -0,0 +1,74 @@ +--- +title: Contributing recipes +description: Propose a reusable Roomote system for the Cookbook through a repository issue. +icon: plus +contributor: Name or team +contributor_url: https://example.com/contributor +contributor_company: Company +contributor_company_url: https://example.com/company +--- + +Use this skeleton when proposing a Cookbook recipe. Replace every placeholder +and remove the comments before opening a +[Cookbook recipe issue](https://github.com/RooCodeInc/Roomote/issues/new?template=cookbook-recipe.yml). +Do not open a pull request unless a maintainer invites you to. Fill in the +contributor fields in the frontmatter and repeat the contributor in the +Overview metadata. If the recipe comes from another team, use those fields for +the attribution. + +````markdown +--- +title: Outcome-first recipe title +description: One sentence explaining the finished system and why it matters. +icon: lucide-icon-name +contributor: Name or team +contributor_url: https://example.com/contributor +contributor_company: Company +contributor_company_url: https://example.com/company +--- + +## Overview + + + +Overview paragraph. + +- **Trigger**: Trigger type +- **Setup time**: About N minutes +- **Requires**: Product access, integrations, permissions +- **Serves**: Teams or roles +- **Cooked By**: [Name or team](https://example.com/contributor) from [Company](https://example.com/company) + +## Ingredients + + + +- Ingredient + +## Steps + + + +1. First step. + +## Paste-ready configuration + + + +```text +Configuration or prompt +``` + +## Variations + + + +- Variation + + + +**Pairs well with:** [Related recipe](/cookbook/example) +```` + +Before submitting, test every paste block against the current product and make +sure the recipe never relies on a prompt alone to enforce a security boundary. diff --git a/apps/docs/cookbook/vendor-outage-triage.mdx b/apps/docs/cookbook/vendor-outage-triage.mdx new file mode 100644 index 000000000..a2a8627dc --- /dev/null +++ b/apps/docs/cookbook/vendor-outage-triage.mdx @@ -0,0 +1,91 @@ +--- +title: Evaluate outage impact +description: Filter vendor status noise by comparing each incident with your real code, regions, and feature usage. +contributor: Matt Rubens +contributor_url: https://github.com/mrubens +contributor_company: Roomote +contributor_company_url: https://roomote.dev +--- + +## Overview + +Every vendor you depend on publishes status updates, and almost none of them +affect you, until one does. Pipe them into one channel and let Roomote read each +incident against your actual code: which SDKs you call, which regions you run +in, and which features you use. You stop triaging vendor noise by hand and only +hear about the outages that matter. This is how we run it at Roo. + +- **Trigger**: Channel event +- **Setup time**: About 20 minutes +- **Requires**: Admin access, Slack or Discord +- **Serves**: On-call, Support +- **Cooked By**: [Matt Rubens](https://github.com/mrubens) + +## Ingredients + +- A Slack or Discord channel such as `#vendor-status` receiving vendor status + feeds. Most vendors offer Subscribe via Slack, RSS-to-channel, or + email-to-channel. +- [Auto-respond channels](/automations#channel-automations) +- An [environment](/environments) covering the repositories that use these + vendors +- Roomote invited to the channel on Slack, or able to see it on Discord + +## Steps + +1. Create `#vendor-status` and subscribe it to every upstream status page you care about. +2. Invite Roomote to the channel. +3. Under **Settings > Automations > Auto-respond to channels**, add the channel. +4. Paste the launch criteria and instructions below. +5. Post a fake incident and confirm a task launches. Then post a scheduled-maintenance notice and confirm it does not. + +## Launch criteria + +Paste this into the channel's **Launch criteria** field: + +```text +Launch only for messages reporting a new incident, a worsening incident, or an +incident that regressed after being resolved, from one of our upstream vendors. + +Do not launch for scheduled-maintenance announcements, "monitoring" or +"resolved" updates to an incident already investigated, changelog or marketing +posts, or duplicate notifications about the same incident. + +Treat a message as an escalation when it adds affected components, expands +impact, or reports a worse status than before. When unsure whether an incident +could plausibly touch something we depend on in production, launch: a wasted +check is cheaper than a missed outage. +``` + +## Instructions + +Paste this into the channel's **Instructions** field. Roomote gives these +instructions to every task launched from the channel. + +```text +A vendor has posted a status incident. Determine whether it affects us: + +1. Identify the vendor and the affected components, regions, and features + from the message. +2. Search the codebase for how we actually use this vendor: SDKs, API + endpoints, features, and regions we depend on. +3. Compare our real usage against what the incident says is affected. +4. Reply in the thread with a clear verdict: + - "Affects us": which features or code paths, likely user impact, and a + suggested action. + - "Safe to ignore": why our usage is not touched. + +Keep it short. The on-call engineer reads this thread. Do not page anyone. +``` + +## Variations + +- Name the vendors explicitly in the criteria to ignore feeds subscribed to just in case. +- Ask Roomote to describe how to verify recovery whenever the verdict is **Affects us**. +- Use a multi-repository environment so the usage search covers every service. + +Auto-respond channels support Slack and Discord today. On Teams or Telegram, +forward status events to a supported channel or mention Roomote from a workflow. + +**Pairs well with:** [CI failure auto-fix](/cookbook/ci-failure-auto-fix) · +[support channel](/cookbook/support-channel) diff --git a/apps/docs/docs.json b/apps/docs/docs.json index b9229ce28..c369d0646 100644 --- a/apps/docs/docs.json +++ b/apps/docs/docs.json @@ -48,6 +48,10 @@ "group": "Using Roomote", "pages": ["how-roomote-works", "use-cases", "tasks", "file-attachments"] }, + { + "group": "Cookbook", + "pages": ["cookbook/index", "cookbook/template"] + }, { "group": "Provider Configuration", "pages": [ diff --git a/apps/docs/integrations/better-stack.mdx b/apps/docs/integrations/better-stack.mdx index 7778e3eef..62cc38b66 100644 --- a/apps/docs/integrations/better-stack.mdx +++ b/apps/docs/integrations/better-stack.mdx @@ -23,3 +23,7 @@ Admins connect Better Stack once from **Settings > Integrations**. Roomote uses Better Stack as task context for investigation and triage. Code changes, validation, and review still happen through the normal Roomote task and repository workflow. + +## Recipes using this + +- [Triage customer issues](/cookbook/support-channel) diff --git a/apps/docs/integrations/grafana.mdx b/apps/docs/integrations/grafana.mdx index c1147bdd0..32c0c0a91 100644 --- a/apps/docs/integrations/grafana.mdx +++ b/apps/docs/integrations/grafana.mdx @@ -25,3 +25,7 @@ instance URL and a shared service account token. The current Grafana integration is read-only. It gives Roomote monitoring context during a task, but it does not create dashboards, edit alerts, or change Grafana configuration. + +## Recipes using this + +- [Triage customer issues](/cookbook/support-channel) diff --git a/apps/docs/integrations/neon.mdx b/apps/docs/integrations/neon.mdx index e7236bcf8..08c2a3310 100644 --- a/apps/docs/integrations/neon.mdx +++ b/apps/docs/integrations/neon.mdx @@ -23,3 +23,7 @@ need it. Neon gives Roomote database context inside the task. Keep any repository changes and human review on the normal Roomote and Git workflow. + +## Recipes using this + +- [Triage customer issues](/cookbook/support-channel) diff --git a/apps/docs/integrations/sentry.mdx b/apps/docs/integrations/sentry.mdx index bd4e5c7c9..3d63d153e 100644 --- a/apps/docs/integrations/sentry.mdx +++ b/apps/docs/integrations/sentry.mdx @@ -22,3 +22,7 @@ Admins connect Sentry once from **Settings > Integrations**. Sentry gives Roomote incident and performance context during a task. It can also support scheduled read-only Sentry triage. The final decision, code change, and review still happen in the normal task and repository flow. + +## Recipes using this + +- [Triage customer issues](/cookbook/support-channel) diff --git a/apps/docs/integrations/snowflake.mdx b/apps/docs/integrations/snowflake.mdx index 1490ab1c0..dfc1bc6be 100644 --- a/apps/docs/integrations/snowflake.mdx +++ b/apps/docs/integrations/snowflake.mdx @@ -32,3 +32,7 @@ when the key is encrypted. Snowflake provides shared data warehouse context inside Roomote tasks. Engineering changes and approvals still happen through your normal task and repository review flow. + +## Recipes using this + +- [Triage customer issues](/cookbook/support-channel) diff --git a/apps/docs/integrations/supabase.mdx b/apps/docs/integrations/supabase.mdx index fbc8ec20e..8581ff3c9 100644 --- a/apps/docs/integrations/supabase.mdx +++ b/apps/docs/integrations/supabase.mdx @@ -23,3 +23,7 @@ when they need it. Supabase gives Roomote read-only database context during a task. Code changes, migrations, and review still go through your normal engineering workflow. + +## Recipes using this + +- [Triage customer issues](/cookbook/support-channel) diff --git a/apps/docs/package.json b/apps/docs/package.json index 8723bb0ca..8ce330940 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -3,9 +3,15 @@ "version": "0.0.3", "private": true, "scripts": { - "dev": "mint dev", - "validate": "mint validate", - "check-links": "mint broken-links", - "check": "mint validate && mint broken-links" + "generate-cookbook-index": "node scripts/generate-cookbook-index.mjs", + "check-cookbook-index": "node scripts/generate-cookbook-index.mjs --check", + "dev": "pnpm run generate-cookbook-index && pnpm dlx --package mint@4.2.650 mint dev", + "validate": "pnpm run generate-cookbook-index && pnpm dlx --package mint@4.2.650 mint validate", + "check-links": "pnpm dlx --package mint@4.2.650 mint broken-links", + "check": "pnpm run validate && pnpm run check-links", + "build": "pnpm run generate-cookbook-index && pnpm dlx --package mint@4.2.650 mint validate" + }, + "dependencies": { + "yaml": "^2.9.0" } } diff --git a/apps/docs/scripts/generate-cookbook-index.mjs b/apps/docs/scripts/generate-cookbook-index.mjs new file mode 100644 index 000000000..dd85ff042 --- /dev/null +++ b/apps/docs/scripts/generate-cookbook-index.mjs @@ -0,0 +1,103 @@ +import { readdir, readFile, writeFile } from 'node:fs/promises'; +import { basename, dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { parse } from 'yaml'; + +const scriptDirectory = dirname(fileURLToPath(import.meta.url)); +const cookbookDirectory = join(scriptDirectory, '..', 'cookbook'); +const indexPath = join(cookbookDirectory, 'index.mdx'); +const tableStart = '{/* cookbook-recipes:start */}'; +const tableEnd = '{/* cookbook-recipes:end */}'; + +const requiredFields = ['title', 'description', 'contributor']; + +function parseFrontmatter(source, fileName) { + const match = source.match(/^---\s*\n([\s\S]*?)\n---\s*(?:\n|$)/); + + if (!match) { + throw new Error(`Missing frontmatter in ${fileName}`); + } + + const metadata = parse(match[1]); + + for (const field of requiredFields) { + if (typeof metadata[field] !== 'string' || metadata[field].trim() === '') { + throw new Error(`Missing ${field} in ${fileName}`); + } + } + + return metadata; +} + +function escapeTableCell(value) { + return value.replaceAll('|', '\\|').replaceAll('\n', ' ').trim(); +} + +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} + +function renderLinkedValue(value, url) { + const text = escapeTableCell(value); + return url ? `[${text}](${url})` : text; +} + +async function readRecipe(fileName) { + const source = await readFile(join(cookbookDirectory, fileName), 'utf8'); + const metadata = parseFrontmatter(source, fileName); + const slug = `/cookbook/${basename(fileName, '.mdx')}`; + + return { + title: metadata.title, + description: metadata.description, + contributor: metadata.contributor, + contributorUrl: metadata.contributor_url, + contributorCompany: metadata.contributor_company, + contributorCompanyUrl: metadata.contributor_company_url, + slug, + }; +} + +function renderTable(recipes) { + const rows = recipes + .sort((left, right) => left.title.localeCompare(right.title)) + .map((recipe) => { + return `| [${escapeTableCell(recipe.title)}](${recipe.slug}) | ${escapeTableCell(recipe.description)} |`; + }); + + return ['| Recipe | Use to |', '| --- | --- |', ...rows].join( + '\n', + ); +} + +const recipeFiles = (await readdir(cookbookDirectory)) + .filter((fileName) => fileName.endsWith('.mdx')) + .filter((fileName) => !['index.mdx', 'template.mdx'].includes(fileName)) + .sort(); +const recipes = await Promise.all(recipeFiles.map(readRecipe)); +const indexSource = await readFile(indexPath, 'utf8'); +const tablePattern = new RegExp( + `${escapeRegExp(tableStart)}[\\s\\S]*?${escapeRegExp(tableEnd)}`, +); + +if (!tablePattern.test(indexSource)) { + throw new Error('Cookbook index is missing the generated table markers'); +} + +const generatedTable = `${tableStart}\n${renderTable(recipes)}\n${tableEnd}`; +const nextIndexSource = indexSource.replace(tablePattern, generatedTable); +const checkOnly = process.argv.includes('--check'); + +if (nextIndexSource !== indexSource) { + if (checkOnly) { + console.error( + 'Cookbook index is out of date; run generate-cookbook-index.', + ); + process.exitCode = 1; + } else { + await writeFile(indexPath, nextIndexSource); + console.log(`Updated cookbook index with ${recipes.length} recipes`); + } +} else { + console.log(`Cookbook index is up to date with ${recipes.length} recipes`); +} diff --git a/apps/docs/skills.mdx b/apps/docs/skills.mdx index 91318deca..d8be6d2fd 100644 --- a/apps/docs/skills.mdx +++ b/apps/docs/skills.mdx @@ -47,6 +47,9 @@ Good custom skills include: - a database migration review guide - a customer-escalation triage playbook +The [support channel recipe](/cookbook/support-channel) shows a complete custom +skill with launch criteria and a production-safe investigation flow. + If the instruction is only one sentence, it probably belongs in [Agent Guidance](/agent-guidance), [environment guidance](/environments), or the task prompt instead. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b785dcc49..4219f5bc3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -451,7 +451,11 @@ importers: specifier: ^4.1.1 version: 4.1.1(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.13.1)(jsdom@26.1.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(vite@7.3.5(@types/node@24.13.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.20.4)(yaml@2.9.0)) - apps/docs: {} + apps/docs: + dependencies: + yaml: + specifier: ^2.9.0 + version: 2.9.0 apps/preview-proxy: dependencies: