Skip to content

Latest commit

Β 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Nycto πŸ¦‰

Nycto is a GitHub Action that triages new issues using Anthropic. When an issue is opened, Nycto:

  1. Searches for similar issues and existing workarounds
  2. Explores the source code to find where the problem lives
  3. Posts a structured comment with a solution, code investigation, and next steps
  4. Escalates complex design issues by applying a configurable label

Activity is traced to Opik for observability. Viewers can rate each response with a πŸ‘/πŸ‘Ž reaction, which is synced back to Opik as human feedback β€” see Response feedback.

Setup

1. Configure secrets and variables

In your repository settings, add:

Secrets (Settings β†’ Secrets and variables β†’ Actions β†’ Secrets):

Secret Description
ANTHROPIC_API_KEY Anthropic API key
OPIK_API_KEY Opik API key

The github.token built-in is used for GitHub access β€” no personal access token or GitHub App required. Comments will appear as github-actions[bot].

Variables (Settings β†’ Secrets and variables β†’ Actions β†’ Variables):

Variable Description
NYCTO_GITHUB_REPO_OWNER Repository owner (e.g. comet-ml)
NYCTO_GITHUB_REPO_NAME Repository name (e.g. opik)
NYCTO_ESCALATION_TAG Label name for escalated issues (e.g. Escalated request)
OPIK_WORKSPACE Opik workspace name

2. Add the workflow

Create .github/workflows/nycto.yml in your target repository:

name: Nycto Issue Triage

on:
  issues:
    types: [opened]
  workflow_dispatch:
    inputs:
      issue_number:
        description: Issue number to triage
        required: true
        type: number

# One Nycto run per issue at a time
concurrency:
  group: nycto-issue-${{ github.event.issue.number || github.event.inputs.issue_number }}
  cancel-in-progress: false

jobs:
  triage:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    permissions:
      issues: write
      contents: read

    steps:
      - name: Run Nycto
        uses: comet-ml/nycto-repo-agent@main
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          github_token: ${{ github.token }}
        env:
          NYCTO_ESCALATION_TAG: ${{ vars.NYCTO_ESCALATION_TAG }}
          NYCTO_GITHUB_REPO_OWNER: ${{ vars.NYCTO_GITHUB_REPO_OWNER }}
          NYCTO_GITHUB_REPO_NAME: ${{ vars.NYCTO_GITHUB_REPO_NAME }}
          OPIK_API_KEY: ${{ secrets.OPIK_API_KEY }}
          OPIK_WORKSPACE: ${{ vars.OPIK_WORKSPACE }}
          ISSUE_NUMBER: ${{ github.event.issue.number || github.event.inputs.issue_number }}

GitHub App requirements

The GitHub App must have these permissions:

  • Issues: Read & Write (to read issues and post comments)
  • Contents: Read (to read source files)

Configuration reference

Env var Required Description
ANTHROPIC_API_KEY yes Anthropic API key
GITHUB_TOKEN yes GitHub token β€” pass ${{ github.token }} via the action input
NYCTO_GITHUB_REPO_OWNER yes Repo owner login
NYCTO_GITHUB_REPO_NAME yes Repo name
NYCTO_ESCALATION_TAG no Label for escalated issues (default: Escalated request)
OPIK_API_KEY yes Opik API key. Opik is required β€” Nycto sources its system prompt from Opik and traces every run there.
OPIK_WORKSPACE yes Opik workspace name
NYCTO_FEEDBACK_SINCE_DAYS no Feedback sync only: how many days back to scan issues for πŸ‘/πŸ‘Ž reactions (default: 7)
ISSUE_NUMBER no Override issue number (auto-detected from event payload)
NYCTO_MODEL no Anthropic model ID (default: claude-sonnet-4-6)
NYCTO_MAX_TOKENS no Max response tokens (default: 8096)
NYCTO_SYSTEM_PROMPT no Override the system prompt inline. Supports $repo_owner, $repo_name, $escalation_tag placeholders.
NYCTO_PROMPT_FILE no Path to a file containing the system prompt (same placeholders supported). Takes effect only when NYCTO_SYSTEM_PROMPT is not set.
NYCTO_OPIK_PROMPT_NAME no Name of the Opik-managed prompt Nycto uses as its system prompt (default: nycto-system-prompt). If no prompt by this name exists in the project, Nycto auto-creates it from the built-in base prompt on first run. The Opik body is then used verbatim β€” no variable substitution β€” so edit it in the Opik UI to change behavior. For the GitHub Action, set via the opik_prompt_name action input rather than env: β€” see the Opik example below.
NYCTO_OPIK_PROMPT_VERSION no Pin a specific Opik prompt version (e.g. v3). Defaults to the latest version. For the GitHub Action, set via the opik_prompt_version action input.

Customizing the system prompt

Nycto always sources its system prompt from Opik (Opik is required). On the first run for a project, if no prompt named NYCTO_OPIK_PROMPT_NAME (default nycto-system-prompt) exists in the project, Nycto creates it from a local base prompt and then uses the Opik copy verbatim on every run.

The base prompt β€” used only to seed Opik that first time β€” is resolved from NYCTO_SYSTEM_PROMPT (inline) > NYCTO_PROMPT_FILE (path to a file) > the built-in default. These three placeholders are substituted before the text is stored in Opik, so the stored prompt is fully resolved (no $-variables remain):

Placeholder Value
$repo_owner Repository owner login
$repo_name Repository name
$escalation_tag Value of NYCTO_ESCALATION_TAG

Once the Opik prompt exists, it is the source of truth β€” changing NYCTO_SYSTEM_PROMPT / NYCTO_PROMPT_FILE no longer affects an already-seeded prompt. To change Nycto's behavior after bootstrap, edit the prompt in the Opik UI (see Using an Opik-managed prompt).

Example: prompt file in the workflow

Create .github/nycto-prompt.txt in your target repository:

You are Nycto πŸ¦‰, a triage agent for $repo_owner/$repo_name.

For each new issue:
1. Search for duplicates using search_issues.
2. Identify the relevant source files with list_directory and get_file_contents.
3. Reply with a short summary, the affected file(s), and a suggested fix.

If the fix requires a breaking API change, call apply_label("$escalation_tag") before replying.

Keep responses concise and technical. Do not use filler phrases.

Then pass it to Nycto in your workflow:

      - name: Run Nycto
        uses: comet-ml/nycto-repo-agent@main
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          github_token: ${{ github.token }}
        env:
          NYCTO_ESCALATION_TAG: ${{ vars.NYCTO_ESCALATION_TAG }}
          NYCTO_GITHUB_REPO_OWNER: ${{ vars.NYCTO_GITHUB_REPO_OWNER }}
          NYCTO_GITHUB_REPO_NAME: ${{ vars.NYCTO_GITHUB_REPO_NAME }}
          OPIK_API_KEY: ${{ secrets.OPIK_API_KEY }}
          OPIK_WORKSPACE: ${{ vars.OPIK_WORKSPACE }}
          NYCTO_PROMPT_FILE: ${{ github.workspace }}/.github/nycto-prompt.txt

Example: inline prompt via NYCTO_SYSTEM_PROMPT

For shorter prompts you can set the value directly as a GitHub Actions variable (Settings β†’ Secrets and variables β†’ Actions β†’ Variables):

      - name: Run Nycto
        uses: comet-ml/nycto-repo-agent@main
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          github_token: ${{ github.token }}
        env:
          NYCTO_ESCALATION_TAG: ${{ vars.NYCTO_ESCALATION_TAG }}
          NYCTO_GITHUB_REPO_OWNER: ${{ vars.NYCTO_GITHUB_REPO_OWNER }}
          NYCTO_GITHUB_REPO_NAME: ${{ vars.NYCTO_GITHUB_REPO_NAME }}
          OPIK_API_KEY: ${{ secrets.OPIK_API_KEY }}
          OPIK_WORKSPACE: ${{ vars.OPIK_WORKSPACE }}
          NYCTO_SYSTEM_PROMPT: ${{ vars.NYCTO_SYSTEM_PROMPT }}

When both NYCTO_SYSTEM_PROMPT and NYCTO_PROMPT_FILE are set, NYCTO_SYSTEM_PROMPT takes precedence.

Using an Opik-managed prompt

Nycto's system prompt lives in Opik as a versioned artifact you can evaluate with Opik's Test Suite and improve with the Opik prompt optimizer, without redeploying the action. This is the default and only path β€” Nycto bootstraps the prompt automatically (see Customizing the system prompt), so you don't have to create it by hand.

Bootstrap (automatic): the first run with no existing prompt creates nycto-system-prompt (version v1) from the base prompt. Nothing to do.

Pre-create it (optional): to control the body up front, create a prompt in the Opik UI before the first run. Nycto uses it verbatim, so write any repo-specific values (owner, repo name, escalation tag) directly into the text. Use the same name you pass as opik_prompt_name (default nycto-system-prompt).

Reference a specific name/version from the workflow:

      - name: Run Nycto
        uses: comet-ml/nycto-repo-agent@main
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          github_token: ${{ github.token }}
          opik_prompt_name: nycto-system-prompt
          # opik_prompt_version: v3  # optional; omit to use the latest version
        env:
          NYCTO_ESCALATION_TAG: ${{ vars.NYCTO_ESCALATION_TAG }}
          NYCTO_GITHUB_REPO_OWNER: ${{ vars.NYCTO_GITHUB_REPO_OWNER }}
          NYCTO_GITHUB_REPO_NAME: ${{ vars.NYCTO_GITHUB_REPO_NAME }}
          OPIK_API_KEY: ${{ secrets.OPIK_API_KEY }}
          OPIK_WORKSPACE: ${{ vars.OPIK_WORKSPACE }}
          ISSUE_NUMBER: ${{ github.event.issue.number || github.event.inputs.issue_number }}

Seed precedence (first run only): NYCTO_SYSTEM_PROMPT > NYCTO_PROMPT_FILE > built-in default. Once the Opik prompt exists, Opik is the source of truth. If a fetch fails transiently (e.g. network error), Nycto logs a warning and falls back to the local base prompt for that run so triage still completes.

Iterating: edit the prompt in Opik to publish a new version. Without NYCTO_OPIK_PROMPT_VERSION set, the next Nycto run picks it up automatically; with a pinned version, the run continues to use that version until you bump the value.

Response feedback

Anyone viewing an issue can rate Nycto's triage comment by adding a πŸ‘ or πŸ‘Ž reaction to it on GitHub. Those reactions are recorded in Opik as a human feedback score named user_feedback on the comment's trace:

  • 1.0 = all πŸ‘, 0.0 = all πŸ‘Ž, otherwise the ratio πŸ‘ / (πŸ‘ + πŸ‘Ž) (e.g. 3 πŸ‘ and 1 πŸ‘Ž β†’ 0.75). Reactions other than πŸ‘/πŸ‘Ž are ignored.
  • The score carries a reason that attributes the votes by GitHub login, e.g. πŸ‘ 2 (alice, bob) / πŸ‘Ž 1 (carol) from GitHub, so you can see who reacted in the Opik UI alongside the trace.

How it works. GitHub fires no event when a reaction is added, so a scheduled workflow polls recent issues every 30 minutes, reads the reaction counts on Nycto's comments, and upserts the score. Each Nycto comment carries a hidden marker (<!-- nycto-feedback trace_id=… -->) that maps it back to its Opik trace. The sync is idempotent β€” re-running simply recomputes the score from current reactions β€” so feedback lands in Opik within one cron interval and self-corrects as votes change.

Enabling it. The feedback sync ships as a second action published from this repo, comet-ml/nycto-repo-agent/actions/feedback, alongside the triage action. Add a scheduled workflow to the repo that runs Nycto β€” it reuses the same OPIK_API_KEY secret and OPIK_WORKSPACE value as the triage action:

name: Nycto Feedback Sync

on:
  schedule:
    - cron: '*/30 * * * *'  # every 30 minutes
  workflow_dispatch:
    inputs:
      since_days:
        description: How many days back to scan issues for reactions
        required: false
        default: '7'
        type: string

concurrency:
  group: nycto-feedback-sync
  cancel-in-progress: false

jobs:
  sync-feedback:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    permissions:
      issues: read
      contents: read
    steps:
      - name: Sync reactions to Opik
        uses: comet-ml/nycto-repo-agent/actions/feedback@main
        with:
          github_token: ${{ github.token }}
          since_days: ${{ github.event.inputs.since_days || '7' }}
        env:
          OPIK_API_KEY: ${{ secrets.OPIK_API_KEY }}
          OPIK_WORKSPACE: ${{ vars.OPIK_WORKSPACE }}

Trigger it manually from the Actions tab for an immediate sync.

Scan window. GitHub does not bump an issue's updated_at when a reaction is added, so the sync only re-checks issues with other activity within NYCTO_FEEDBACK_SINCE_DAYS (default 7). Reactions on otherwise-quiet older issues may be missed β€” run the workflow manually with a larger since_days to backfill. Because the upsert is idempotent, re-syncing is always safe.

Testing

Use the manual trigger workflow in this repo's Actions tab (Test Nycto (Manual)) to run Nycto against a specific issue number before enabling the automatic trigger.

Local development

The code is an installable package under src/nycto/. Install it (with dev extras) in editable mode:

pip install -e ".[dev]"

# Copy and fill in the template
cp .env.example .env

# Run triage locally (console script registered by the install).
# Equivalent to `python -m nycto.triage`.
nycto-triage

Run the unit tests and linters with pytest, ruff check ., and mypy src/nycto.

.env.example:

ANTHROPIC_API_KEY=
GITHUB_TOKEN=github_pat_...
NYCTO_ESCALATION_TAG=Escalated request
NYCTO_GITHUB_REPO_OWNER=owner
NYCTO_GITHUB_REPO_NAME=name
ISSUE_NUMBER=123
OPIK_WORKSPACE=comet-all
OPIK_API_KEY=
# Optional: override the system prompt (supports $repo_owner, $repo_name, $escalation_tag)
# NYCTO_SYSTEM_PROMPT=
# NYCTO_PROMPT_FILE=
# Optional: fetch the system prompt from Opik (body used verbatim β€” no variable substitution)
# NYCTO_OPIK_PROMPT_NAME=
# NYCTO_OPIK_PROMPT_VERSION=

About

Nycto is a Github Repository Agent that can respond to issues

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages