Skip to content

Support global context paths by merging built-in defaults with user-specified paths #149

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,20 @@ You can configure OpenCode using environment variables:
}
```

### Context Paths
By default, OpenCode loads a set of built-in context files (e.g. `.github/copilot-instructions.md`, `.cursor/rules/`, `OPENCODE.md`, etc.) to provide additional guidance to the AI assistant. You can extend or override these by adding a `contextPaths` array to your configuration:
```json
{
"contextPaths": [
"docs/context.md",
"./project-instructions.md",
"/some/absolute/global-instructions.md"
]
}
```
Relative paths (those not starting with `/`) are resolved against the configured working directory, while absolute paths are used as-is. Duplicate entries are automatically removed.


## Supported AI Models

OpenCode supports a variety of AI models from different providers:
Expand Down
44 changes: 44 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ func Load(workingDir string, debug bool) (*Config, error) {

setProviderDefaults()

// Process and normalize context paths
processContextPaths()

// Apply configuration to the struct
if err := viper.Unmarshal(cfg); err != nil {
return cfg, fmt.Errorf("failed to unmarshal config: %w", err)
Expand Down Expand Up @@ -324,6 +327,40 @@ func setProviderDefaults() {
}
}

// processContextPaths merges built-in defaults and user-specified context paths,
// normalizes both relative and absolute paths, and deduplicates the final list.
func processContextPaths() {
// Combine built-in defaults with any user-specified context paths
userPaths := viper.GetStringSlice("contextPaths")
paths := append(defaultContextPaths, userPaths...)

normalized := make([]string, 0, len(paths))
seen := make(map[string]bool)

for _, p := range paths {
var absPath string
var err error

if filepath.IsAbs(p) {
absPath = p
} else {
absPath, err = filepath.Abs(filepath.Join(cfg.WorkingDir, p))
if err != nil {
logging.Warn("failed to resolve context path", "path", p, "error", err)
continue
}
}

if !seen[absPath] {
seen[absPath] = true
normalized = append(normalized, absPath)
}
}

// Update viper with normalized paths
viper.Set("contextPaths", normalized)
}

// hasAWSCredentials checks if AWS credentials are available in the environment.
func hasAWSCredentials() bool {
// Check for explicit AWS credentials
Expand Down Expand Up @@ -708,6 +745,13 @@ func WorkingDirectory() string {
}
return cfg.WorkingDir
}
// ContextPaths returns the list of configured and normalized context paths.
func ContextPaths() []string {
if cfg == nil {
panic("config not loaded")
}
return cfg.ContextPaths
}

func UpdateAgentModel(agentName AgentName, modelID models.ModelID) error {
if cfg == nil {
Expand Down