Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ Scheduled and event-driven automation execution for OpenHands Cloud. This servic
- **API Key Management**: Per-user API keys for secure automation access
- **Run History**: Track automation runs with status and results

## Recommended automations

Reusable prompt-preset automation ideas live in [`examples/recommended-automations/`](examples/recommended-automations/).

- [Slack+GitHub+Linear Daily Organization](examples/recommended-automations/slack-github-linear-daily-organization.md) — reconcile GitHub PRs/issues with Linear work and recent Slack context into a daily plan.

## Development

### Prerequisites
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Slack+GitHub+Linear Daily Organization

A recommended prompt-preset automation that runs every morning to reconcile GitHub work with Linear planning and summarize actionable Slack context into a personal daily plan.

This automation is intentionally written with placeholders only. Replace bracketed values such as `[GITHUB_USERNAME]`, `[LINEAR_ASSIGNEE_QUERY]`, `[GITHUB_ORG_OR_REPO_SCOPE]`, `[SLACK_RECIPIENT_QUERY]`, and `[IANA_TIMEZONE]` when creating the automation.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The placeholder list includes [GITHUB_USERNAME], [LINEAR_ASSIGNEE_QUERY], [GITHUB_ORG_OR_REPO_SCOPE], [SLACK_RECIPIENT_QUERY], and [IANA_TIMEZONE], but there is no [LINEAR_TEAM_QUERY] (or [LINEAR_PROJECT_QUERY]). Task 2 step 3 will tell the agent to pick "the appropriate Linear team/project" with no guidance, which means it will guess. In multi-team workspaces that silently routes new issues to the wrong team. Suggest adding a placeholder here and a corresponding Identity and scope line such as:

- Linear team: resolve by searching for [LINEAR_TEAM_QUERY]. Do not guess if multiple teams exist.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The placeholder list includes [GITHUB_USERNAME], [LINEAR_ASSIGNEE_QUERY], [GITHUB_ORG_OR_REPO_SCOPE], [SLACK_RECIPIENT_QUERY], and [IANA_TIMEZONE], but there is no [LINEAR_TEAM_QUERY] (or [LINEAR_PROJECT_QUERY]). Task 2 step 3 will tell the agent to pick "the appropriate Linear team/project" with no guidance, which means it will guess. In multi-team workspaces that silently routes new issues to the wrong team. Suggest adding a placeholder here and a corresponding Identity and scope line such as:

- Linear team: resolve by searching for [LINEAR_TEAM_QUERY]. Do not guess if multiple teams exist.


## When to use this

Use this automation when you want OpenHands to:

- Review your open GitHub pull requests and ensure each PR is connected to a GitHub issue.
- Import or match relevant open GitHub issues into Linear.
- Keep active Linear work aligned with open PRs.
- Search recent Slack context for requests related to active Linear issues.
- Send a concise daily plan to the configured Slack recipient.

This is a good fit for a prompt-preset automation because it requires judgment: conservative issue matching, priority selection, Slack-context summarization, and deciding what to recommend first.

## Suggested schedule

```json
{
"type": "cron",
"schedule": "0 7 * * *",
"timezone": "[IANA_TIMEZONE]"
}
```

## Prompt

```text
You are running a daily GitHub/Linear/Slack organization automation.

Schedule context:
- This automation runs every morning at 7:00 AM in [IANA_TIMEZONE].
- Treat "today" and "past 1-3 days" in [IANA_TIMEZONE].

Important safety and access rules:
1. First, verify that you have working access to GitHub, Linear, and Slack using the available official tools/APIs. A minimal successful read for each service is enough.
2. If any one of GitHub, Linear, or Slack is unavailable, missing credentials, or returns an authorization error, stop immediately. Do not make partial updates. If Slack is available, send the configured Slack recipient a short message saying which service was unavailable and that no changes were made; otherwise finish with that error.
3. Prefer official APIs/MCP tools over browser interaction. Do not browse web UIs unless no API/tool path exists.
4. When posting to Slack or creating/updating human-readable external-service content, include a short disclosure that the content was generated by an AI agent (OpenHands) on behalf of the user.

Identity and scope:
- GitHub user to inspect: [GITHUB_USERNAME].
- GitHub issue scope: [GITHUB_ORG_OR_REPO_SCOPE]. Examples: visible repositories in one or more organizations, or an explicit allowlist of repositories.
- Linear assignee: resolve by searching for [LINEAR_ASSIGNEE_QUERY]. Do not guess an ID if multiple plausible matches exist.
- Slack recipient for the final daily plan: resolve by searching for [SLACK_RECIPIENT_QUERY], or use the current authenticated Slack user if that is the intended recipient.

Task 1 — Ensure the user's open PRs are associated with GitHub issues:
1. Find all open pull requests authored by [GITHUB_USERNAME] across the configured GitHub scope.
2. For each PR, determine whether it is already associated with a GitHub issue. Count an association if the PR body has a clear issue reference or closing keyword (for example, #123, owner/repo#123, fixes, closes, or resolves), or if GitHub's API exposes linked/closing issues.
3. If a PR has no associated issue:
a. Search open issues in the same repository for an obvious matching issue using the PR title, branch name, and summary. Only treat an issue as obvious if the title/topic clearly matches; do not force weak matches.
b. If an obvious open issue exists, use that issue.
c. If none exists, create a new GitHub issue in the same repository summarizing the PR's purpose and linking back to the PR. Include an AI disclosure in the issue body.
d. Update the PR description to include a non-closing association such as "Related issue: #123" or "Related issue: owner/repo#123" for cross-repo references. Preserve the existing PR description. Avoid "Fixes", "Closes", or "Resolves" unless the PR already used a closing keyword or the issue clearly should close when the PR merges.

Task 2 — Ensure GitHub issues are represented in Linear:
1. Find all open GitHub issues, excluding PRs, in the configured GitHub issue scope.
2. For each issue, verify that it has a corresponding Linear issue. Match by GitHub issue URL first, then by exact repository/name/number and title if needed.
3. If no Linear issue exists, create one in the appropriate Linear team/project using the GitHub issue title, URL, repository, labels, and a concise summary. Include an AI disclosure in the Linear issue description. Choose an appropriate priority for newly created Linear issues using this rubric:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

"The appropriate Linear team/project" is undefined at this point. The Identity and scope block above (line ~47) specifies assignee and assignee query, but not team. Without a [LINEAR_TEAM_QUERY] placeholder in scope the agent has to infer the team, which is unreliable in workspaces with multiple teams. This line should reference the placeholder once it is added.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

"The appropriate Linear team/project" is undefined at this point. The Identity and scope block above (line ~47) specifies assignee and assignee query, but not team. Without a [LINEAR_TEAM_QUERY] placeholder in scope the agent has to infer the team, which is unreliable in workspaces with multiple teams. This line should reference the placeholder once it is added.

- Urgent: security, production outage, data loss, severe user-blocking regression, active incident.
- High: important bug/regression, release blocker, broadly affecting users, high-value requested work.
- Medium: normal feature/bug/task with moderate impact.
- Low: cleanup, docs, nice-to-have, unclear/low-impact backlog.
- No priority only if there is insufficient information.
4. For every GitHub issue that has one or more open PRs associated with it, ensure the corresponding Linear issue is assigned to the configured Linear assignee and has a started/In Progress status. If the Linear issue is already completed or canceled, do not reopen it; mention this in the final report instead.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This step silently changes assignee and status on Linear issues the user may not own. If [GITHUB_ORG_OR_REPO_SCOPE] covers an entire org with dozens of repos this could touch many issues at once, overwriting existing assignees and moving issues to In Progress without human review. This side effect is not mentioned in the "When to use this" section or the safety rules.

Suggest adding a warning bullet under "When to use this":

⚠️ Automatically reassigns and moves Linear issues to In Progress for every GitHub issue with an open PR. Verify scope is restricted to your own repositories before enabling org-wide.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This step silently changes assignee and status on Linear issues the user may not own. If [GITHUB_ORG_OR_REPO_SCOPE] covers an entire org with dozens of repos this could touch many issues at once, overwriting existing assignees and moving issues to In Progress without human review. This side effect is not mentioned in the "When to use this" section or the safety rules.

Suggest adding a warning bullet under "When to use this":

⚠️ Automatically reassigns and moves Linear issues to In Progress for every GitHub issue with an open PR. Verify scope is restricted to your own repositories before enabling org-wide.

5. Do not downgrade or otherwise change priorities of existing Linear issues merely because they seem wrong. If an existing priority is missing and the issue is actively in progress due to an open PR, you may set a reasonable priority. If a priority seems unclear or incorrect, flag it in the final Slack report rather than changing it.

Task 3 — Check Slack context for active Linear issues:
1. Inspect active Linear issues assigned to the configured assignee and not completed/canceled, especially urgent, high-priority, and in-progress issues.
2. Search Slack public content and, if available in the tool configuration, private/DM-accessible content for the last 1-3 days for requests, mentions, or discussions related to those Linear issue identifiers, issue titles, linked GitHub issues/PRs, and relevant repository names.
3. Summarize actionable Slack requests/discussions. Include links to Slack messages/threads when the Slack tooling provides them.
4. Do not expose private Slack content beyond what is necessary for the configured recipient's own daily plan.

Task 4 — Produce and send the daily plan:
1. Review all active Linear issues assigned to the configured assignee, prioritizing Urgent then High then Medium then Low, while also considering Slack requests, open PR status, blockers, and issue age.
2. Create a concise plan for what the recipient should work on today, focusing on the most urgent and important issues first.
3. Include:
- Top 3-5 recommended focus items with Linear identifiers/titles and links.
- Any GitHub PR issue-association work performed.
- Any GitHub issues imported into Linear.
- Any Linear issues moved to In Progress or assigned to the configured assignee because an open PR exists.
- Any Slack requests/discussions from the past 1-3 days relevant to active Linear issues.
- Any issue priorities that are unclear or appear incorrect; explicitly say you did not change those priorities.
- Any access or matching limitations.
4. Send the report to the configured Slack recipient as a DM if possible. If DM is not possible, use the best available Slack destination for that recipient. Include the AI disclosure in the message.
5. Finish with a short execution summary including counts of PRs checked, PRs updated, GitHub issues created, GitHub issues imported to Linear, Linear issues updated, and Slack discussions found.

Be careful and conservative: avoid duplicate GitHub issues, duplicate Linear issues, weak associations, or broad destructive changes.
```

## Prompt-preset request example

```bash
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/prompt" \
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
-H "Content-Type: application/json" \
-d @- <<'JSON'
{
"name": "Slack+GitHub+Linear Daily Organization",
"prompt": "Paste the anonymized prompt above after replacing bracketed placeholders.",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This "prompt" value is itself placeholder/meta text — a user who copy-pastes the curl command as-is will send the literal string "Paste the anonymized prompt above..." to the API, not the actual prompt. The API will accept it but the resulting automation will not do anything useful.

Options:

  • Replace with an explicit note above the block: # Replace the prompt value below with the full text from the ## Prompt section above, properly escaped as a JSON string.
  • Or inline a truncated hint: "Your full prompt text here (replace with content from the Prompt section above)" — still illustrative but harder to accidentally use verbatim.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This "prompt" value is itself placeholder/meta text — a user who copy-pastes the curl command as-is will send the literal string "Paste the anonymized prompt above..." to the API, not the actual prompt. The API will accept it but the resulting automation will not do anything useful.

Options:

  • Replace with an explicit note above the block: # Replace the prompt value below with the full text from the ## Prompt section above, properly escaped as a JSON string.
  • Or inline a truncated hint: "Your full prompt text here (replace with content from the Prompt section above)" — still illustrative but harder to accidentally use verbatim.

"trigger": {
"type": "cron",
"schedule": "0 7 * * *",
"timezone": "[IANA_TIMEZONE]"
},
"timeout": 1800
}
JSON
```
Loading