Skip to content
Merged
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
12 changes: 12 additions & 0 deletions src/agents/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ListTrelloCards,
PostTrelloComment,
ReadTrelloCard,
UpdateChecklistItem,
UpdateTrelloCard,
formatCardData,
} from '../gadgets/trello/index.js';
Expand Down Expand Up @@ -110,8 +111,10 @@ async function buildAgentContext(
log: ReturnType<typeof createAgentLogger>,
): Promise<AgentContextData> {
// Build prompt context for template rendering
const cardUrl = `https://trello.com/c/${cardId}`;
const promptContext: PromptContext = {
cardId,
cardUrl,
projectId: project.id,
storiesListId: project.trello?.lists?.stories,
processedLabelId: project.trello?.labels?.processed,
Expand Down Expand Up @@ -205,6 +208,7 @@ function createAgentBuilderWithGadgets(
new ListTrelloCards(),
new GetMyRecentActivity(),
new AddChecklistToCard(),
new UpdateChecklistItem(),
);
}

Expand Down Expand Up @@ -370,13 +374,21 @@ export async function executeAgent(

log.info('Agent completed', { cardId, iterations: result.iterationCount, cost: result.cost });

// Extract PR URL from output (gh pr create outputs the URL)
const prUrlMatch = result.output.match(/https:\/\/github\.com\/[^\s]+\/pull\/\d+/);
const prUrl = prUrlMatch ? prUrlMatch[0] : undefined;
if (prUrl) {
log.info('PR URL extracted', { prUrl });
}

// Get zipped log buffer before returning
fileLogger.close();
const logBuffer = await fileLogger.getZippedBuffer();

return {
success: true,
output: result.output,
prUrl,
logBuffer,
cost: result.cost,
};
Expand Down
1 change: 1 addition & 0 deletions src/agents/prompts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const eta = new Eta({ views: templatesDir, autoEscape: false });
export interface PromptContext {
// Common
cardId?: string;
cardUrl?: string;
projectId?: string;

// Briefing-specific
Expand Down
17 changes: 12 additions & 5 deletions src/agents/prompts/templates/briefing.eta
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,13 @@ You are running in a cloned copy of the project repository. Before creating stor
- Include TLDR, acceptance criteria, and technical notes in description (use emoji formatting)
- **IMPORTANT:** Save the returned URL for each card (e.g., `https://trello.com/c/abc123`)
5. **Add interactive checklists** using `AddChecklistToCard`:
- For EACH card you create, call `AddChecklistToCard` with the card ID
- Use "✅ Acceptance Criteria" as the checklist name
- Add each acceptance criterion as a checklist item
- For EACH card you create, call `AddChecklistToCard` for acceptance criteria:
- Use "✅ Acceptance Criteria" as the checklist name
- Add each acceptance criterion as a checklist item
- For cards that depend on other stories, also call `AddChecklistToCard` for dependencies:
- Use "🔗 Dependencies" as the checklist name
- Add each dependency as a checklist item (use card title or URL)
- Skip this checklist for foundational stories with no dependencies
6. **Post summary comment** using `PostTrelloComment`:
- Post a comment on the ORIGINAL card listing all created stories
- Use markdown links: `[Story Title](URL)` for each card
Expand Down Expand Up @@ -129,7 +133,9 @@ Use this template with **emoji section headers** and **bold key terms** for read
- [Things explicitly NOT included in this story]
```

**IMPORTANT:** After creating each card, ALWAYS call `AddChecklistToCard` to create an interactive checklist with the acceptance criteria items.
**IMPORTANT:** After creating each card, ALWAYS call `AddChecklistToCard` to create interactive checklists:
1. "✅ Acceptance Criteria" checklist with acceptance criteria items (always)
2. "🔗 Dependencies" checklist with cards that must be completed first (if any)

## Summary Comment Format

Expand Down Expand Up @@ -203,7 +209,8 @@ If the user asks you to update stories you previously created:
- ALWAYS use `ReadTrelloCard` first
- ALWAYS explore the codebase before creating stories
- ALWAYS create stories using `CreateTrelloCard` - don't just output text
- ALWAYS call `AddChecklistToCard` after creating each card to add interactive checklists
- ALWAYS call `AddChecklistToCard` after creating each card to add "✅ Acceptance Criteria" checklist
- ALWAYS add "🔗 Dependencies" checklist to stories that depend on other stories
- ALWAYS use emoji section headers (🎯, ✅, 🔧, 🚫) and **bold key terms** in descriptions
- ALWAYS include a 🎯 TLDR section at the top of every card description
- ALWAYS post a summary comment with markdown links to all created cards
Expand Down
66 changes: 56 additions & 10 deletions src/agents/prompts/templates/implementation.eta
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ You are an expert software engineer implementing features based on a detailed pl
7. **Create commits** via Tmux: `git add . && git commit -m "feat: description"`
8. **Push the branch** via Tmux: `git push -u origin HEAD`
9. **Create a PR** via Tmux: `gh pr create --title "..." --body "..."`
10. **Mark acceptance criteria complete** using UpdateChecklistItem for each criterion you've implemented
11. **Post summary comment** on the Trello card describing what was implemented and linking to the PR

## Mandatory Exploration Before Implementation

Expand Down Expand Up @@ -76,12 +78,11 @@ Use standard git commands and GitHub CLI (`gh`) via Tmux for all version control
- `git push -u origin HEAD` - push branch to remote

**GitHub CLI (`gh`) commands:**
- `gh pr create --fill` - create PR auto-filling title/body from commits (simplest)
- `gh pr create --title "Title" --body "Description" --base dev` - create with explicit values
- `gh pr create --title "Title" --body "Description"` - create PR with explicit values (required)
- `gh pr view` - view current PR
- `gh pr list` - list open PRs

**IMPORTANT:** Always use `--fill` or provide `--title` and `--body` to avoid interactive prompts.
**IMPORTANT:** Always provide `--title` and `--body` to avoid interactive prompts. Do NOT use `--fill`.

## Commit Message Format

Expand All @@ -97,18 +98,62 @@ Example: `feat: add user authentication endpoint`

## PR Description Format

```markdown
## Summary
[Brief description of what this PR does]
When creating your PR, you MUST use this format:

```bash
gh pr create --title "type: brief description" --body "## Summary
Brief description of what this PR implements.

## Changes
- [List of changes]
- Main change 1
- Main change 2

## Testing
- [How to test]
- How to test these changes

## Related
- Trello card: [URL]
- Trello card: <%= it.cardUrl %>
"
```

**CRITICAL PR Requirements:**
- The PR description MUST include the Trello card link: `<%= it.cardUrl %>`
- The description should be comprehensive enough to understand the PR without reading all the code
- Always use explicit `--title` and `--body` flags, never `--fill`

## Completion Process

After creating the PR, complete these steps:

### 1. Mark Acceptance Criteria Complete

Use `UpdateChecklistItem` to mark each completed acceptance criterion:
1. Read the card again to get checklist item IDs
2. For each criterion you've implemented, call `UpdateChecklistItem` with state="complete"

### 2. Post Summary Comment

Use `PostTrelloComment` to post a summary on the Trello card:

```markdown
## ✅ Implementation Complete

**PR:** [PR Title](PR_URL)

### What was implemented
- [Key feature/change 1]
- [Key feature/change 2]

### Key decisions
- [Decision 1 and why]
- [Decision 2 and why]

### Testing
- All tests passing
- Lint and type checks passing

### Notes
- [Any issues encountered or things to be aware of]
```

## Rules
Expand All @@ -125,4 +170,5 @@ Example: `feat: add user authentication endpoint`
- NEVER write comprehensive test suites when the card asks for targeted tests - match scope to the plan
- Use meaningful commit messages following conventional commits
- Keep commits small and focused
- Post the PR URL to Trello using PostTrelloComment when complete
- ALWAYS mark acceptance criteria complete using UpdateChecklistItem after PR is created
- ALWAYS post a summary comment on the Trello card with PR link and what was implemented
44 changes: 44 additions & 0 deletions src/gadgets/trello/UpdateChecklistItem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Gadget, z } from 'llmist';
import { trelloClient } from '../../trello/client.js';
import { formatGadgetError } from '../utils.js';

export class UpdateChecklistItem extends Gadget({
name: 'UpdateChecklistItem',
description:
'Update a checklist item state on a Trello card. Use this to mark acceptance criteria as complete or incomplete.',
timeoutMs: 15000,
schema: z.object({
cardId: z.string().describe('The Trello card ID'),
checkItemId: z.string().describe('The checklist item ID to update'),
state: z.enum(['complete', 'incomplete']).describe('The new state for the checklist item'),
}),
examples: [
{
params: {
cardId: 'abc123',
checkItemId: 'item456',
state: 'complete',
},
comment: 'Mark an acceptance criterion as complete',
},
{
params: {
cardId: 'abc123',
checkItemId: 'item789',
state: 'incomplete',
},
comment: 'Mark an acceptance criterion as incomplete',
},
],
}) {
override async execute(params: this['params']): Promise<string> {
try {
await trelloClient.updateChecklistItem(params.cardId, params.checkItemId, params.state);

const action = params.state === 'complete' ? 'marked complete' : 'marked incomplete';
return `Checklist item ${params.checkItemId} ${action} on card ${params.cardId}`;
} catch (error) {
return formatGadgetError('updating checklist item', error);
}
}
}
1 change: 1 addition & 0 deletions src/gadgets/trello/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export { CreateTrelloCard } from './CreateTrelloCard.js';
export { ListTrelloCards } from './ListTrelloCards.js';
export { GetMyRecentActivity } from './GetMyRecentActivity.js';
export { AddChecklistToCard } from './AddChecklistToCard.js';
export { UpdateChecklistItem } from './UpdateChecklistItem.js';
13 changes: 13 additions & 0 deletions src/trello/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,19 @@ export const trelloClient = {
}));
},

async updateChecklistItem(
cardId: string,
checkItemId: string,
state: 'complete' | 'incomplete',
): Promise<void> {
logger.debug('Updating checklist item', { cardId, checkItemId, state });
await getClient().cards.updateCardCheckItem({
id: cardId,
idCheckItem: checkItemId,
state,
});
},

async getCardCustomFieldItems(cardId: string): Promise<CustomFieldItem[]> {
logger.debug('Fetching card custom field items', { cardId });
const apiKey = process.env.TRELLO_API_KEY;
Expand Down
5 changes: 5 additions & 0 deletions src/triggers/trello/webhook-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ async function executeAgent(
if (cardId) {
await safeAddLabel(cardId, project.trello.labels.processing);
await safeRemoveLabel(cardId, project.trello.labels.readyToProcess);

// Move to IN PROGRESS when implementation starts
if (result.agentType === 'implementation') {
await safeMoveCard(cardId, project.trello.lists.inProgress);
}
}

const agentResult = await runAgent(result.agentType, {
Expand Down