feat: Initial implementation of Simili-bot v0.0.1#1
Conversation
- Create directory structure (cmd/, internal/, DOCS/) - Add implementation plan (DOCS/0.0.1v/plan.md) - Add .env.sample with environment variable templates - Add single-repo-setup.md documentation - Add multi-repo-org-setup.md documentation - Add minimal go.mod and cmd/simili/main.go - Verified: go build and go vet pass
- Add Config, QdrantConfig, EmbeddingConfig, DefaultsConfig structs - Implement Load() with environment variable expansion - Implement LoadWithInheritance() for 'extends' support - Implement mergeConfigs() for parent-child config merging - Add ParseExtendsRef() to parse 'org/repo@branch:path' references - Add FindConfigPath() for auto-discovery of config files - Verified: go build and go vet pass
- Add PendingAction struct with Type, Org, Repo, IssueNumber, Target, timestamps - Add GitStateManager interface for state operations - Implement GitHubStateManager using GitHub Contents API - GetPendingAction: retrieve action by issue - SetPendingAction: create/update action file - DeletePendingAction: remove action file - ListPendingActions: list all actions of a type - Uses orphan branch 'simili-state' for storage - Verified: go build and go vet pass
- Add Step interface with Name() and Run(ctx *Context) methods - Add Context struct with Issue, Config, Result, Metadata - Add Issue, Result, SimilarIssue data structures - Add Pipeline struct with Run() method for sequential step execution - Add ErrSkipPipeline for graceful early termination - Add Registry for dynamic step factory registration - Add preset workflows: issue-triage, similarity-only, index-only - Add ResolveSteps() for config-based workflow selection - Verified: go build and go vet pass
- Add Gatekeeper step for repo config validation - Add VectorDBPrep step for collection verification - Add SimilaritySearch step placeholder for finding similar issues - Add TransferCheck step placeholder for transfer rule evaluation - Add Triage step placeholder for LLM-based analysis - Add ResponseBuilder step for constructing comments - Add ActionExecutor step for executing actions (comments, transfers) - Add Indexer step for adding issues to vector DB - All steps implement pipeline.Step interface - Verified: go build and go vet pass
- Add centered logo and badges - Add feature highlights with emoji icons - Add architecture overview with ASCII diagram - Add quick start guide - Add documentation links - Add development instructions
- Mark Phase 1-3 as completed - Add 'Remaining Work' section for future phases - Reorganize phase numbering
- Add CI workflow (build, test, lint, vet) - Add release workflow with GoReleaser - Add issue templates (bug report, feature request) - Add PR template with checklist - Add discussion templates (general, ideas, Q&A) - Add CONTRIBUTING.md with development guide - Add CODE_OF_CONDUCT.md (Contributor Covenant) - Add SECURITY.md with vulnerability reporting policy
Line 48 used fmt.Sprintf with no format arguments, replaced with string literal.
There was a problem hiding this comment.
Pull request overview
This pull request establishes the foundational architecture for Simili-bot v0.0.1, an AI-powered GitHub issue intelligence tool designed to detect duplicate issues, perform semantic search, and intelligently route issues across repositories.
Changes:
- Core pipeline engine with modular step-based architecture supporting preset workflows and custom step configurations
- Git branch-based state management system using GitHub API for tracking pending actions without cluttering issue comments
- Configuration system with inheritance support for multi-repository organizations via
extendsdirective - Eight pipeline step scaffolds (Gatekeeper, VectorDBPrep, Similarity, TransferCheck, Triage, ResponseBuilder, ActionExecutor, Indexer)
- Comprehensive documentation including setup guides, architecture plans, and community contribution guidelines
- CI/CD workflows for build, test, lint, and automated releases with GoReleaser
Reviewed changes
Copilot reviewed 32 out of 35 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
internal/core/config/config.go |
Configuration loading with YAML parsing, environment variable expansion, and parent-child config merging |
internal/core/pipeline/pipeline.go |
Core pipeline engine with Step interface and Context for data flow between steps |
internal/core/pipeline/registry.go |
Step registry with factory pattern and three preset workflows (issue-triage, similarity-only, index-only) |
internal/core/state/state.go |
State management interface defining pending action operations |
internal/core/state/github.go |
GitHub API-based state manager for reading/writing to orphan branch without local checkout |
internal/steps/*.go |
Eight pipeline step scaffolds with TODO placeholders for actual implementations |
cmd/simili/main.go |
Minimal CLI entry point placeholder |
go.mod, go.sum |
Go module definition with single yaml.v3 dependency |
README.md |
Professional README with architecture overview and quick start guide |
DOCS/*.md |
Setup guides for single-repo and multi-repo deployments plus implementation plan |
CONTRIBUTING.md, CODE_OF_CONDUCT.md, SECURITY.md |
Community governance documents |
.github/workflows/*.yml |
CI workflow for build/test/lint and release workflow with GoReleaser |
.github/ISSUE_TEMPLATE/*.yml |
Issue and discussion templates for bug reports, feature requests, and Q&A |
.env.sample |
Environment variable template with documentation |
assets/logo.png |
Project logo |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Check if the repository is configured | ||
| repoConfig := findRepoConfig(ctx) | ||
| if repoConfig == nil { | ||
| ctx.Result.Skipped = true | ||
| ctx.Result.SkipReason = "repository not configured" | ||
| return pipeline.ErrSkipPipeline | ||
| } |
There was a problem hiding this comment.
The gatekeeper behavior may be confusing for single-repository setups. When the repositories list is empty (which is valid for single-repo usage), the gatekeeper will skip all issues because findRepoConfig returns nil. Consider allowing processing when the repositories list is empty, treating it as "allow all" for backwards compatibility and simpler single-repo configurations.
| ```yaml | ||
| # .github/simili.yaml | ||
|
|
||
| qdrant: | ||
| url: "${QDRANT_URL}" | ||
| api_key: "${QDRANT_API_KEY}" | ||
| collection: "my-repo-issues" # Unique name for this repo | ||
|
|
||
| embedding: | ||
| provider: "gemini" | ||
| api_key: "${GEMINI_API_KEY}" | ||
|
|
||
| # Use a preset workflow for simplicity | ||
| workflow: "issue-triage" | ||
|
|
||
| defaults: | ||
| similarity_threshold: 0.65 | ||
| max_similar_to_show: 5 | ||
| ``` |
There was a problem hiding this comment.
The single-repository setup guide is missing the required repositories configuration. Based on the gatekeeper implementation (internal/steps/gatekeeper.go:27-33), if the repositories list is empty, all issues will be skipped with "repository not configured". The example configuration should include:
repositories:
- org: "your-org"
repo: "your-repo"
enabled: trueAlternatively, the gatekeeper logic should be updated to allow processing when the repositories list is empty (treating it as "allow all").
| ```yaml | ||
| qdrant: | ||
| url: "${QDRANT_URL}" | ||
| api_key: "${QDRANT_API_KEY}" | ||
| collection: "my-repo-issues" | ||
|
|
||
| embedding: | ||
| provider: "gemini" | ||
| api_key: "${GEMINI_API_KEY}" | ||
|
|
||
| workflow: "issue-triage" | ||
|
|
||
| defaults: | ||
| similarity_threshold: 0.65 | ||
| max_similar_to_show: 5 | ||
| ``` |
There was a problem hiding this comment.
The Quick Start configuration example is missing the required repositories field. Based on the gatekeeper implementation (internal/steps/gatekeeper.go:27-33), if the repositories list is empty, all issues will be skipped with "repository not configured". The example should include the repositories configuration or the gatekeeper should be updated to handle empty repository lists.
| func (m *GitHubStateManager) setHeaders(req *http.Request) { | ||
| req.Header.Set("Authorization", "Bearer "+m.token) | ||
| req.Header.Set("Accept", "application/vnd.github+json") | ||
| req.Header.Set("X-GitHub-Api-Version", "2022-11-28") |
There was a problem hiding this comment.
The GitHub API requires a Content-Type header for PUT requests. Without this header, the API may reject the request or fail to parse the JSON payload correctly. Add req.Header.Set("Content-Type", "application/json") to the setHeaders method or directly before making PUT/DELETE requests.
| req.Header.Set("X-GitHub-Api-Version", "2022-11-28") | |
| req.Header.Set("X-GitHub-Api-Version", "2022-11-28") | |
| req.Header.Set("Content-Type", "application/json") |
|
|
||
| Instances of abusive, harassing, or otherwise unacceptable behavior may be | ||
| reported to the community leaders responsible for enforcement at | ||
| **[INSERT CONTACT METHOD]**. |
There was a problem hiding this comment.
The Code of Conduct contact method placeholder needs to be filled in. Replace [INSERT CONTACT METHOD] with an actual contact email or other reporting mechanism for Code of Conduct violations.
| **[INSERT CONTACT METHOD]**. | |
| **code-of-conduct@example.com**. |
| - name: Test | ||
| run: go test -v -race -coverprofile=coverage.out ./... |
There was a problem hiding this comment.
The CI workflow will fail on the test step because there are no test files in the repository. Since this is v0.0.1 with scaffold implementations, consider either:
- Adding a skip condition for the test step when no tests exist, or
- Adding basic test files (even if they're minimal/placeholder tests)
Current command go test -v -race -coverprofile=coverage.out ./... will return exit code 0 if there are no test files, so this may actually pass, but it provides no coverage validation.
| return nil, fmt.Errorf("unexpected encoding: %s", result.Encoding) | ||
| } | ||
|
|
||
| return base64.StdEncoding.DecodeString(result.Content) |
There was a problem hiding this comment.
The GitHub API returns base64-encoded content with newlines for formatting. These newlines must be removed before decoding. Replace line 149 with:
content := strings.ReplaceAll(result.Content, "\n", "")
return base64.StdEncoding.DecodeString(content)Without this, base64 decoding will fail for file contents.
| return base64.StdEncoding.DecodeString(result.Content) | |
| content := strings.ReplaceAll(result.Content, "\n", "") | |
| return base64.StdEncoding.DecodeString(content) |
| ### How to Report | ||
|
|
||
| 1. **Do NOT** open a public GitHub issue for security vulnerabilities | ||
| 2. Email your findings to **[INSERT SECURITY EMAIL]** |
There was a problem hiding this comment.
The security contact email placeholder needs to be filled in before release. Replace [INSERT SECURITY EMAIL] with an actual contact email address for security vulnerability reports.
| 2. Email your findings to **[INSERT SECURITY EMAIL]** | |
| 2. Email your findings to **security@example.com** |
| if child.Defaults.CrossRepoSearch { | ||
| result.Defaults.CrossRepoSearch = true | ||
| } |
There was a problem hiding this comment.
The merge logic for CrossRepoSearch is incorrect. A child config with cross_repo_search: false cannot override a parent's cross_repo_search: true because the condition only checks if the child value is true. This should check if the field was explicitly set. Consider using a pointer type *bool for this field to distinguish between explicitly set false and unset (which would allow proper merging).
| if child.Defaults.CrossRepoSearch { | |
| result.Defaults.CrossRepoSearch = true | |
| } | |
| // CrossRepoSearch: always take the child value so it can override parent true -> false and vice versa | |
| result.Defaults.CrossRepoSearch = child.Defaults.CrossRepoSearch |
| payload["sha"] = sha | ||
| } | ||
|
|
||
| body, _ := json.Marshal(payload) |
There was a problem hiding this comment.
Error handling silently ignores JSON marshaling errors. If json.Marshal(payload) fails, the underscore assignment discards the error and proceeds with potentially invalid data. This should return the error: body, err := json.Marshal(payload); if err != nil { return err }
| body, _ := json.Marshal(payload) | |
| body, err := json.Marshal(payload) | |
| if err != nil { | |
| return err | |
| } |
- Fix base64 decoding by removing newlines from GitHub API response - Add proper error handling for JSON marshaling operations - Add Content-Type header for GitHub API PUT/DELETE requests - Allow empty repositories list for single-repo mode in gatekeeper - Fix CrossRepoSearch merge logic to allow child false to override parent true - Add repositories configuration to documentation examples - Add enabled field to multi-repo setup examples - Replace placeholder contact information in CODE_OF_CONDUCT.md and SECURITY.md - Add initial test suite for config package to enable CI validation
Description
This PR establishes the foundation for Simili-bot, an AI-powered GitHub issue intelligence tool.
Type of Change
Changes Made
Core Implementation
extendssupport for multi-repo inheritanceDocumentation
Community Files
Testing
go build ./...successfullygo vet ./...successfullyChecklist