> ## Documentation Index
> Fetch the complete documentation index at: https://code.storage/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# repo.grep()

> Search for patterns within repository content using regular expressions.

> [!WARNING]
>
> This page documents the earlier Code Storage SDKs: `@pierre/storage`, `pierre-storage`, and
> `code-storage-go`. New code uses the [Pierre SDK](https://code.storage/docs/sdks.md). To move code to the new SDK, use the
> [`pierre-migrate`
> skill](https://github.com/pierrecomputer/skills/tree/main/skills/pierre-migrate).

Beta

```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
// Basic pattern search
const results = await repo.grep({
  query: { pattern: 'TODO' },
});

console.log(`Found ${results.matches.length} files with matches`);
results.matches.forEach((match) => {
  console.log(`${match.path}:`);
  match.lines.forEach((line) => {
    if (line.type === 'match') {
      console.log(`  ${line.lineNumber}: ${line.text}`);
    }
  });
});

// Search inside an ephemeral ref
const previewResults = await repo.grep({
  ref: 'preview/pr-123',
  ephemeral: true,
  query: { pattern: 'TODO' },
});

// Advanced search with filtering and context
const advancedResults = await repo.grep({
  ref: 'main',
  query: {
    pattern: 'function\\s+\\w+Error',
    caseSensitive: true,
  },
  paths: ['src/'],
  fileFilters: {
    includeGlobs: ['**/*.js', '**/*.ts'],
    excludeGlobs: ['**/node_modules/**', '**/*.test.js'],
  },
  context: { before: 2, after: 2 },
  limits: { maxLines: 200, maxMatchesPerFile: 10 },
  pagination: { limit: 50 },
});

// Handle pagination
let cursor = advancedResults.nextCursor;
while (cursor && advancedResults.hasMore) {
  const moreResults = await repo.grep({
    query: { pattern: 'TODO' },
    pagination: { cursor, limit: 50 },
  });
  console.log('Next page:', moreResults.matches);
  cursor = moreResults.nextCursor;
}

// Paging is done, but the search itself may have hit the server cap
if (advancedResults.incompleteResults) {
  console.log('Results capped at maxLines, narrow the search to see more');
}
```

```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
# Basic pattern search
results = await repo.grep(pattern="TODO")

print(f"Found {len(results['matches'])} files with matches")
for match in results['matches']:
    print(f"{match['path']}:")
    for line in match['lines']:
        if line['type'] == 'match':
            print(f"  {line['line_number']}: {line['text']}")

# Search inside an ephemeral ref
preview_results = await repo.grep(
    pattern="TODO",
    ref="preview/pr-123",
    ephemeral=True,
)

# Advanced search with all options
advanced_results = await repo.grep(
    pattern=r"function\s+\w+Error",
    ref="main",
    paths=["src/"],
    case_sensitive=True,
    file_filters={
        "include_globs": ["**/*.py", "**/*.js"],
        "exclude_globs": ["**/tests/**", "**/node_modules/**"],
        "extension_filters": [".py", ".js", ".ts"]
    },
    context={"before": 2, "after": 2},
    limits={"max_lines": 200, "max_matches_per_file": 10},
    pagination={"limit": 50}
)

# Handle pagination
cursor = advanced_results.get('next_cursor')
while cursor and advanced_results['has_more']:
    more_results = await repo.grep(
        pattern="TODO",
        pagination={"cursor": cursor, "limit": 50}
    )
    print('Next page:', more_results['matches'])
    cursor = more_results.get('next_cursor')

# Paging is done, but the search itself may have hit the server cap
if advanced_results['incomplete_results']:
    print('Results capped at max_lines, narrow the search to see more')
```

```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
// Basic pattern search
results, err := repo.Grep(context.Background(), storage.GrepOptions{
	Query: storage.GrepQuery{Pattern: "TODO"},
})
fmt.Printf("Found %d files with matches", len(results.Matches))

// Search inside an ephemeral ref
ephemeral := true
preview, err := repo.Grep(context.Background(), storage.GrepOptions{
	Ref:       "preview/pr-123",
	Ephemeral: &ephemeral,
	Query:     storage.GrepQuery{Pattern: "TODO"},
})

caseSensitive := true
before := 2
after := 2
maxLines := 200
maxMatches := 10
pageLimit := 50

// Advanced search with filters
advanced, err := repo.Grep(context.Background(), storage.GrepOptions{
	Ref: "main",
	Query: storage.GrepQuery{
		Pattern:       `function\s+\w+Error`,
		CaseSensitive: &caseSensitive,
	},
	Paths: []string{"src/"},
	FileFilters: &storage.GrepFileFilters{
		IncludeGlobs:     []string{"**/*.go", "**/*.ts"},
		ExcludeGlobs:     []string{"**/node_modules/**", "**/*.test.ts"},
		ExtensionFilters: []string{".go", ".ts"},
	},
	Context: &storage.GrepContext{Before: &before, After: &after},
	Limits:  &storage.GrepLimits{MaxLines: &maxLines, MaxMatchesPerFile: &maxMatches},
	Pagination: &storage.GrepPagination{Limit: &pageLimit},
})

// Handle pagination
cursor := advanced.NextCursor
for cursor != "" && advanced.HasMore {
	moreLimit := 50
	more, err := repo.Grep(context.Background(), storage.GrepOptions{
		Query:      storage.GrepQuery{Pattern: "TODO"},
		Pagination: &storage.GrepPagination{Cursor: cursor, Limit: &moreLimit},
	})
	fmt.Println("Next page:", more.Matches)
	cursor = more.NextCursor
}

// Paging is done, but the search itself may have hit the server cap
if advanced.IncompleteResults {
	fmt.Println("Results capped at MaxLines, narrow the search to see more")
}
```

## Options

**query.pattern** `string` *required*

Regular expression pattern to search for

**query.caseSensitive** `string`

Whether search should be case sensitive (default: true)

**ref** `string`

Git reference to search in (defaults to repository's default branch)

**ephemeral** `boolean`

Resolve `ref` against the ephemeral namespace instead of the default namespace (default: `false`)

**paths** `string`

Array/List of Git pathspecs to limit search scope

**fileFilters.includeGlobs** `string`

Glob patterns for files to include

**fileFilters.excludeGlobs** `string`

Glob patterns for files to exclude

**fileFilters.extensionFilters** `string`

File extensions to filter by (e.g., `['.js', '.py']`)

**context.before** `string`

Number of lines to include before each match

**context.after** `string`

Number of lines to include after each match

**limits.maxLines** `string`

Maximum total output lines the server will collect for a search (default: 2000, max: 2000 - the
default is already the maximum). You can lower it for cheap previews, but you cannot raise it. If
a search produces more lines than this cap, the result is capped and the response sets
`incomplete_results` to `true`.

**limits.maxMatchesPerFile** `string`

Maximum matches per file (default: 200)

**pagination.cursor** `string`

Pagination cursor from previous response

**pagination.limit** `string`

Maximum results per page (default: 200)

**ttl** `string`

Token TTL. Token TTL in seconds.

## Response

The grep response includes:

* `query`: Echo of search parameters with resolved defaults
* `repo`: Information about the searched ref and commit
* `matches`: Array of files with matching lines
  * Each match contains `path` and `lines` array
  * **TypeScript**: Lines include `lineNumber`, `text`, and `type` (`'match'` or `'context'`)
  * **Python**: Lines include `line_number`, `text`, and `type` (`'match'` or `'context'`)
* **TypeScript**: `hasMore` and `nextCursor` for pagination, `incompleteResults` for the search cap
* **Python**: `has_more` and `next_cursor` for pagination, `incomplete_results` for the search cap

## Incomplete results vs. pagination

Two different fields report two different things:

* `has_more` is about **pagination**. The server collected more matches than fit in this page. Keep
  requesting with `next_cursor` until `has_more` is `false`. you will receive everything the server
  collected.
* `incomplete_results` is about the **search cap** from raw output of `git grep`. The search
  produced more than `limits.maxLines` output lines (default and maximum: 2000), so the server
  stopped collecting at the cap. Matches beyond the cap exist in the repository but **cannot be
  retrieved by paging**.

The two combine independently: a capped result can still span several pages
(`has_more: true, incomplete_results: true`), and paging it to the end (`has_more: false`) does not
necessarily make it complete.

When `incomplete_results` is `true`, narrow the search instead of paging harder: use a more specific
`pattern`, restrict `paths`, or add `fileFilters`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.