# GoTask Usage Guide for AI Agents

## Purpose

This guide provides AI agents with best practices for working with GoTask (Task) task automation in operator repositories. Use this when creating, modifying, or executing tasks defined in Taskfile.yml.

## Target Audience

AI agents (Claude Code, Cursor, Copilot, etc.) working with projects that use GoTask for task automation and build orchestration.

## Core Principles

### 1. Task Discovery First

Always check existing tasks before creating new ones:

````bash
# List all available tasks
task --list

# View tasks in specific namespace
task gotask
task yaml
task claude
```text

### 2. Use Existing Utilities

The `task gotask` namespace provides utilities for task development:

**Task Development:**

- `task gotask:new:task` - Create new task interactively
- `task gotask:new:script` - Create TypeScript task script
- `task gotask:validate` - Validate Taskfile syntax
- `task gotask:format` - Format default task output

**Templates:**

- `task gotask:template:basic` - Basic task template
- `task gotask:template:build` - Build task template
- `task gotask:template:test` - Test task template

**Documentation:**

- `task gotask:docs:generate` - Generate documentation
- `task gotask:docs:view` - View best practices
- `task gotask:docs:edit` - Edit best practices

### 3. Prefer Scripts Over Inline Commands

**❌ Bad - Complex bash in taskfile:**

```yaml
tasks:
  lint:
    cmds:
      - |
        if command -v prettier &> /dev/null; then
          FILES=$(find . -name "*.yml" -not -path "*/node_modules/*")
          for file in $FILES; do
            prettier --check "$file" || exit 1
          done
        else
          echo "prettier not found"
          exit 1
        fi
```text

**✅ Good - Delegate to TypeScript:**

```yaml
tasks:
  lint:
    desc: 'Lint YAML files'
    cmds:
      - bun run ./src/tasks/yaml/lint.ts
    env:
      FILES: '{{.FILES | default "*.yml"}}'
```text

## Parameter Syntax Standards

### Preferred: Shell-Style Parameters

**Long format (recommended):**

```bash
task yaml:lint --files="*.yml"
task yaml:lint --linter=prettier
task build --target=production
```text

**Short format (for aliases):**

```bash
task yaml:lint -f="*.yml"
task yaml:lint -l=prettier
task build -t=production
```text

**Positional (single parameter):**

```bash
task yaml:lint -- *.yml
task test -- unit
```text

### Legacy: Environment Variable Style

**⚠️  Backward compatible but not preferred:**

```bash
# Still works but avoid in new code
task yaml:lint FILES="*.yml"
task build TARGET=production
```text

### Implementation in Taskfile

Define parameters using GoTask variables:

```yaml
tasks:
  lint:
    desc: 'Lint files with optional pattern'
    vars:
      PATTERN: '{{.files | default "*.yml"}}'  # Map --files flag
      LINTER: '{{.linter | default "auto"}}'   # Map --linter flag
    cmds:
      - bun run ./scripts/lint.ts
    env:
      FILES: '{{.PATTERN}}'
      LINTER: '{{.LINTER}}'
```text

Usage:

```bash
# Shell-style (preferred)
task lint --files="src/**/*.yml" --linter=prettier

# Legacy (supported)
task lint FILES="src/**/*.yml" LINTER=prettier
```text

## Task Structure Best Practices

### 1. Namespace Organization

```yaml
# Main Taskfile.yml
version: '3'

includes:
  yaml:
    taskfile: ./tasks/yaml.yml
    dir: .

  claude:
    taskfile: ./tasks/claude.yml
    dir: .

  gotask:
    taskfile: ./tasks/gotask.yml
    dir: .
```text

### 2. Task Definition Pattern

```yaml
version: '3'

vars:
  DEFAULT_PATTERN: "*.yml,*.yaml"

tasks:
  default:
    desc: 'Show available tasks'
    aliases: [help, h]
    silent: true
    cmds:
      - |
        echo "Task Category Name"
        echo "Command                  Alias    Description"
        echo "─────────────────────────────────────────────"
        echo "task category:action     a        Description"

  action:
    desc: 'Task description'
    aliases: [a]
    silent: true
    vars:
      PARAM: '{{.param | default .DEFAULT_PATTERN}}'
    cmds:
      - bun run ./src/tasks/category/action.ts
    env:
      PARAMETER_NAME: '{{.PARAM}}'
```text

### 3. Default Task Help

Every task file should have a `default` task showing available commands:

```yaml
tasks:
  default:
    desc: 'Show available YAML tasks'
    aliases: [help, h]
    silent: true
    cmds:
      - |
        # Use color codes for better readability
        GREEN='\033[0;32m'
        YELLOW='\033[0;33m'
        BOLD='\033[1m'
        NC='\033[0m'

        echo -e "${BOLD}Category Name${NC}"
        echo ""
        echo -e "Command                  Alias    Description"
        echo "─────────────────────────────────────────────"
        echo -e "${GREEN}task cat:action${NC}      ${YELLOW}a${NC}        Do something"
```text

## Table Formatting with Colors

### The Challenge

Creating aligned tables with ANSI color codes is challenging because:

1. **`printf` with width specifiers** counts escape sequences as part of string length
2. **`column -t`** doesn't understand ANSI codes and escapes them
3. Manual spacing with `echo -e` is fragile and breaks easily

### Recommended Solution: Manual Spacing with `echo -e`

Use `echo -e` with careful manual spacing. This is the **only reliable method** that preserves colors.

**Example:**

```yaml
tasks:
  default:
    desc: 'Show available tasks'
    silent: true
    cmds:
      - |
        GREEN='\033[0;32m'
        YELLOW='\033[0;33m'
        BLUE='\033[0;34m'
        BOLD='\033[1m'
        NC='\033[0m'

        echo -e "${BOLD}Project Name${NC}"
        echo ""
        echo "Command                            Alias     Description                              Examples"
        echo "───────────────────────────────────────────────────────────────────────────────────────────────────"
        echo -e "${BOLD}Core Tasks:${NC}"
        echo -e "  ${GREEN}task build${NC}                       ${YELLOW}b${NC}         Build the project"
        echo -e "  ${GREEN}task test${NC}                        ${YELLOW}t${NC}         Run tests"
        echo -e "  ${GREEN}task lint${NC}                        ${YELLOW}l${NC}         Run linter                               FILES=\"...\""
```text

### Column Spacing Guidelines

**Standard column widths:**

- **Command**: ~35 characters (including indentation)
- **Alias**: ~10 characters
- **Description**: ~40 characters
- **Examples**: Flexible (remaining space)

**Tips:**

1. **Use a monospaced font** when editing to visually align columns
2. **Count visible characters only** (ignore ANSI escape codes mentally)
3. **Test with `task`** - run the task to see actual output
4. **Remove empty examples** - Don't use `--` or placeholders for commands without examples
5. **Abbreviate long examples** - Use `"..."` for path patterns instead of full paths

**Example spacing breakdown:**

```bash
# Each section is aligned by counting visible characters
#         Command (35 chars)     Alias(10)  Description (40 chars)             Examples
echo -e "  ${GREEN}task build${NC}                       ${YELLOW}b${NC}         Build the project"
#         ^^indentation
#           ^^^^ ^^^^^ = task build (10 chars)
#                      ^^^^^^^^^^^^^^^ = spaces to reach column 2 (35 - 10 - 2 indent = 23 spaces)
#                                     ^ = b (1 char)
#                                       ^^^^^^^^^ = spaces to reach column 3 (10 - 1 = 9 spaces)
#                                                 ^^^^^^^^^^^^^^^^^^^ = description text
```text

### What NOT to Do

**❌ Using `column -t` with colors:**

```yaml
# This BREAKS colors - escape codes are treated as text
{
  printf "%s|%s|%s\n" "${GREEN}task build${NC}" "${YELLOW}b${NC}" "Build"
} | column -t -s '|'
# Output: \033[0;32mtask build\033[0m  \033[0;33mb\033[0m  Build
```text

**❌ Using `printf` with width specifiers:**

```yaml
# This BREAKS alignment - counts escape codes in width
printf "  %-35s  %-10s  %s\n" "${GREEN}task build${NC}" "${YELLOW}b${NC}" "Build"
# The color codes add ~20 characters, making alignment wrong
```text

**✅ Correct approach:**

```yaml
# Manual spacing with echo -e
echo -e "  ${GREEN}task build${NC}                       ${YELLOW}b${NC}         Build the project"
```text

### Testing Your Table

Always test by running the task:

```bash
task category:help
# or
task category
```text

Look for:

- Misaligned columns
- Color codes appearing as text (escape sequences visible)
- Inconsistent spacing between rows

## Creating New Tasks

### Option 1: Use Interactive Creator

```bash
# Let the utility guide you
task gotask:new:task

# Creates task with proper structure
# Prompts for: name, description, aliases, commands
```text

### Option 2: Use Templates

```bash
# Generate template and modify
task gotask:template:basic > tasks/new-category.yml

# Edit the generated template
# Include in main Taskfile.yml
```text

### Option 3: Manual Creation

Follow this checklist:

1. **Create task file** - `tasks/category.yml`
2. **Define structure** - version, vars, tasks
3. **Add default task** - Help output with color codes
4. **Define actions** - With descriptions and aliases
5. **Delegate to scripts** - TypeScript in `src/tasks/category/`
6. **Include in main** - Add to `Taskfile.yml` includes
7. **Validate syntax** - `task gotask:validate`
8. **Update docs** - Add section to `tasks/README.md`

## TypeScript Task Scripts

### Directory Structure

```text
src/tasks/category/
├── types.ts          # Type definitions
├── utils.ts          # Helper functions
├── action1.ts        # Executable script
├── action2.ts        # Executable script
└── action3.ts        # Executable script

tests/tasks/category/
├── utils.test.ts     # Unit tests
├── action1.test.ts   # Unit tests
└── integration.test.ts
```text

### Script Template

```typescript
#!/usr/bin/env bun

/**
 * Copyright (c) 2024-2025 Company Name
 * All rights reserved.
 */

import { execSync } from 'node:child_process';
import type { ResultType } from './types';
import { helperFunction } from './utils';

/**
 * Main script function
 */
function main(): void {
  console.log('🔧 Starting action...\n');

  // Get parameters from environment
  const param = process.env.PARAM || 'default';

  try {
    // Implementation
    const result = helperFunction(param);

    console.log('✅ Action complete');
    process.exit(0);
  } catch (error) {
    console.error('❌ Action failed:', error);
    process.exit(1);
  }
}

// Run if executed directly
if (import.meta.main) {
  main();
}

export { main };
```text

## Clean Output Standards

### Principle: Only Print What Changes

Tasks should follow a minimal output philosophy - only show information when something changes or when reporting final results. Avoid verbose progress messages, status updates, or unnecessary confirmations.

**Key rules:**

1. **Silent on success** - If everything works as expected, don't print status messages
2. **Show final result** - Print one line showing what happened and the outcome
3. **Error to stderr** - All error messages go to stderr with `>&2`
4. **Use color codes** - Green checkmark for success, red X for errors, yellow for warnings
5. **Include URLs** - Make output actionable by including clickable links

### Output Format Pattern

**Success format:**

```bash
echo -e "${GREEN}✓${NC} Action: result/URL"
```

**Error format:**

```bash
echo -e "${RED}❌ Error description${NC}" >&2
exit 1
```

**Warning format:**

```bash
echo -e "${YELLOW}⚠${NC} Warning: fallback action"
```

### Examples

**❌ Bad - Verbose output:**

```yaml
tasks:
  pr:create:
    cmds:
      - |
        echo "Starting PR creation process..."
        echo "Getting current branch..."
        BRANCH=$(git branch --show-current)
        echo "Current branch: $BRANCH"

        echo "Checking for existing PR..."
        PR=$(gh pr list --head "$BRANCH" --json number -q '.[0].number')

        if [ -n "$PR" ]; then
          echo "Found existing PR #$PR"
          echo "Updating PR title and body..."
          gh pr edit "$PR" --title "$TITLE" --body "$BODY"
          echo "PR updated successfully!"
          echo "PR URL: https://github.com/owner/repo/pull/$PR"
        fi
```

Output:
```
Starting PR creation process...
Getting current branch...
Current branch: feat/new-feature
Checking for existing PR...
Found existing PR #123
Updating PR title and body...
https://github.com/owner/repo/pull/123
PR updated successfully!
PR URL: https://github.com/owner/repo/pull/123
```

**✅ Good - Clean output:**

```yaml
tasks:
  pr:create:
    cmds:
      - |
        GREEN='\033[0;32m'
        NC='\033[0m'

        BRANCH=$(git branch --show-current)
        PR=$(gh pr list --head "$BRANCH" --json number -q '.[0].number')

        if [ -n "$PR" ]; then
          gh pr edit "$PR" --title "$TITLE" --body "$BODY" &>/dev/null
          PR_URL=$(gh pr view "$PR" --json url -q '.url')
          echo -e "${GREEN}✓${NC} Updated: $PR_URL"
        fi
```

Output:
```
✓ Updated: https://github.com/owner/repo/pull/123
```

### Multi-Step Tasks

For tasks with multiple steps, show one status line per significant change:

**Example: PR creation with push**

```yaml
tasks:
  pr:create:
    cmds:
      - |
        GREEN='\033[0;32m'
        YELLOW='\033[0;33m'
        NC='\033[0m'

        # Extract title
        TITLE=$(head -n1 .pr.local.md)
        echo -e "${GREEN}✓${NC} Title: $TITLE"

        # Push branch
        if git push -u origin "$BRANCH" &>/dev/null; then
          echo -e "${GREEN}✓${NC} Branch pushed to origin/$BRANCH"
        else
          echo -e "${YELLOW}⚠${NC} Git push failed (will use gh CLI)"
        fi

        # Create or update PR
        if [ -n "$EXISTING_PR" ]; then
          gh pr edit "$EXISTING_PR" --title "$TITLE" --body "$BODY" &>/dev/null
          echo -e "${GREEN}✓${NC} Updated: $PR_URL"
        else
          PR_URL=$(gh pr create --title "$TITLE" --body "$BODY" --draft)
          echo -e "${GREEN}✓${NC} Created: $PR_URL"
        fi
```

Output:
```
✓ Title: feat(cli): add new command
✓ Branch pushed to origin/feat/new-command
✓ Created: https://github.com/owner/repo/pull/124
```

### Suppressing Command Output

Use output redirection to hide verbose command output:

**Redirect stderr only:**

```bash
git push -u origin "$BRANCH" 2>/dev/null
```

**Redirect both stdout and stderr:**

```bash
git push -u origin "$BRANCH" &>/dev/null
gh pr edit "$PR" --title "$TITLE" &>/dev/null
```

**Capture output for conditional display:**

```bash
OUTPUT=$(command 2>&1)
if [ $? -ne 0 ]; then
  echo "$OUTPUT" >&2
  exit 1
fi
```

### Color Code Standards

Define color codes at the start of each task:

```bash
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'  # No Color
```

**Usage:**

- `GREEN` - Success messages, checkmarks
- `RED` - Errors, failures
- `YELLOW` - Warnings, fallback actions
- `CYAN` - Informational (use sparingly)
- `BOLD` - Headers (help menus only)

### Error Messages

Error messages should be:

1. **Specific** - Say exactly what went wrong
2. **Actionable** - Suggest how to fix it
3. **Concise** - One or two lines maximum

**Example:**

```bash
if [ -z "$GITHUB_TOKEN" ]; then
  echo -e "${RED}❌ GitHub token not found${NC}" >&2
  echo "Set GITHUB_TOKEN in .env" >&2
  exit 1
fi
```

### Summary Output

For tasks that retrieve or process data, show a single summary line:

**❌ Bad:**

```bash
echo "Comments retrieved successfully!"
echo ""
echo "Summary:"
echo "  General comments: 5"
echo "  Code review comments: 12"
echo "  Reviews: 3"
echo "  Total: 20"
echo ""
echo "Log saved to: /path/to/log.txt"
echo ""
echo "View with: cat /path/to/log.txt"
```

**✅ Good:**

```bash
echo -e "${GREEN}✓${NC} Retrieved 20 comments for PR #123 → /path/to/log.txt"
```

## Common Patterns

### 1. File Pattern Discovery

```typescript
// src/tasks/category/utils.ts
export function discoverFiles(patterns: string[]): string[] {
  const files = new Set<string>();

  for (const pattern of patterns) {
    if (pattern.includes('**')) {
      // Recursive glob
      const found = findFilesRecursive(baseDir, filename);
      found.forEach(f => files.add(f));
    } else {
      // Simple pattern via shell
      const matched = execSync('ls ' + pattern, {
        encoding: 'utf-8',
        shell: '/bin/bash'
      }).trim().split('\n');
      matched.forEach(f => files.add(f));
    }
  }

  return Array.from(files).sort();
}
```text

### 2. Tool Detection

```typescript
// src/tasks/category/utils.ts
export function commandExists(command: string): boolean {
  try {
    execSync('command -v ' + command, { stdio: 'pipe' });
    return true;
  } catch {
    return false;
  }
}

export function detectTools() {
  return {
    tool1: commandExists('tool1'),
    tool2: commandExists('tool2'),
    npm: commandExists('npm'),
  };
}
```text

### 3. Environment Variable Handling

```typescript
// Get from environment with defaults
const pattern = process.env.FILES || '*.yml,*.yaml';
const linter = process.env.LINTER || 'auto';

// Parse patterns
const patterns = pattern.split(',').map(p => p.trim());
```text

### 4. Exit Codes

```typescript
// Success
process.exit(0);

// Failure
process.exit(1);

// Usage error
process.exit(2);
```text

### 5. Quiet Output on Success

**Best Practice**: Tasks should be quiet when no issues are found and provide a `VERBOSE` flag for detailed output.

```typescript
// src/tasks/category/action.ts
function main(): void {
  const verbose = process.env.VERBOSE === 'true' || process.env.VERBOSE === '1';

  if (verbose) {
    console.log('🔧 Starting action...\n');
  }

  // Perform checks
  const result = performAction();

  // Only output when there are issues OR in verbose mode
  if (!result.success) {
    console.log('❌ Action failed:\n');
    result.errors.forEach(err => console.log('  ' + err));
    process.exit(1);
  } else {
    if (verbose) {
      console.log('✅ Action completed successfully');
    }
    process.exit(0);
  }
}
```text

**Taskfile Configuration**:

```yaml
tasks:
  action:
    desc: 'Perform action (quiet on success, use VERBOSE=1 for details)'
    vars:
      VERBOSE_FLAG: '{{.VERBOSE | default ""}}'
    cmds:
      - bun run ./src/tasks/category/action.ts
    env:
      VERBOSE: '{{.VERBOSE_FLAG}}'
```text

**Usage**:

```bash
task category:action              # Quiet on success
VERBOSE=1 task category:action    # Show all output
```text

**Why**: This pattern reduces noise in CI/CD pipelines and local development while still allowing detailed output when needed for debugging.

## Validation and Testing

### Before Committing

```bash
# Validate Taskfile syntax
task gotask:validate

# Run affected tests
bun test tests/tasks/category/

# Check task works
task category:action -- test-value
```text

### Test Structure

```typescript
import { describe, expect, it, mock } from 'bun:test';
import { helperFunction } from '../../../src/tasks/category/utils';

describe('category utils', () => {
  it('should process input correctly', () => {
    const result = helperFunction('input');
    expect(result).toBeDefined();
  });
});
```text

## Documentation Requirements

### 1. Task File Comments

```yaml
# YAML Linting & Validation Tasks
# Provides YAML validation, linting, and auto-fixing for all YAML files.

version: '3'
```text

### 2. README.md Section

Add to `tasks/README.md`:

```markdown
### Category Name ([category.yml](category.yml))

Brief description of what this task category provides.

**Commands:**

| Task                    | Alias | Description              |
| ----------------------- | ----- | ------------------------ |
| `task cat:action`       | `a`   | Do something             |
| `task cat:other`        | `o`   | Do something else        |

**Usage:**

\`\`\`bash
# Example command
task cat:action --param="value"

# With short alias
task cat:action -p="value"
\`\`\`
```text

### 3. JSDoc Comments

```typescript
/**
 * Process files matching pattern
 *
 * @param pattern - Glob pattern to match
 * @param options - Processing options
 * @returns Array of processed file paths
 *
 * @example
 * ```typescript
 * const files = processFiles('*.yml', { exclude: ['node_modules'] });
 * ```
 */
export function processFiles(
  pattern: string,
  options: ProcessOptions
): string[] {
  // Implementation
}
```text

## Troubleshooting

### Task Not Found

```bash
# Check if task exists
task --list | grep task-name

# Verify include in main Taskfile
grep "includes:" Taskfile.yml

# Check task file exists
ls tasks/category.yml
```text

### Script Not Executing

```bash
# Check permissions
ls -la src/tasks/category/script.ts

# Make executable
chmod +x src/tasks/category/script.ts

# Run directly to see errors
bun run src/tasks/category/script.ts
```text

### Parameter Not Working

```bash
# Check variable mapping in task
cat tasks/category.yml | grep -A5 "vars:"

# Try with quotes
task category:action --param="value with spaces"

# Check environment in script
bun run -e 'console.log(process.env)' src/tasks/category/script.ts
```text

## When to Use GoTask

### ✅ Good Use Cases

- Build automation
- Development workflows
- CI/CD orchestration
- Linting and validation
- Testing pipelines
- Code generation
- Setup and initialization
- Multi-step processes

### ❌ Not Recommended

- Runtime application logic
- Web servers (use proper frameworks)
- Database migrations (use dedicated tools)
- Complex business logic (use application code)

## Integration with Other Tools

### Git Hooks

```yaml
tasks:
  pre-commit:
    desc: 'Run pre-commit checks'
    cmds:
      - task lint
      - task typecheck
      - task test
```text

### CI/CD

```yaml
tasks:
  ci:
    desc: 'Run CI checks'
    cmds:
      - task lint
      - task typecheck
      - task test
      - task build
      - task semgrep
```text

### IDE Integration

Most IDEs can run GoTask tasks:

- VSCode: Install "Task" extension
- Cursor: Built-in terminal support
- IntelliJ: Configure as External Tool

## Quick Reference

### Essential Commands

```bash
# List all tasks
task --list

# Run task
task category:action

# With parameters (preferred)
task category:action --param="value"

# Legacy style (supported)
task category:action PARAM="value"

# View task help
task category

# Validate taskfiles
task gotask:validate

# Create new task
task gotask:new:task
```text

### File Locations

```text
Taskfile.yml           # Main task runner
tasks/                 # Task definitions
  category.yml         # Category-specific tasks
  README.md            # Task documentation
src/tasks/             # TypeScript implementations
  category/            # Category scripts
    types.ts
    utils.ts
    action.ts
tests/tasks/           # Unit tests
  category/
    utils.test.ts
```text

## Related Documentation

- [tasks/README.md](../../tasks/README.md) - Complete task library reference
- [docs/guides/agents.markdown.md](./agents.markdown.md) - Markdown formatting standards
- [CLAUDE.md](../../CLAUDE.md) - Project instructions for Claude Code
- [GoTask Documentation](https://taskfile.dev) - Official GoTask docs

---

**For AI Agents:** Use this guide when working with GoTask tasks. Always check existing tasks before creating new ones, delegate complex logic to TypeScript, and follow the parameter syntax standards. Use `task gotask` utilities to streamline task development.
````
