A PowerShell SDK for the Glean REST APIs. Every operation in Glean's published OpenAPI specification, as a cmdlet — with an offline mode that needs no credentials and shares its corpus with glean-code-cli.
Import-Module Glean
Invoke-GleanSearch -Query 'quarterly planning' | Select-Object title, urlThat works before you have a token. With no credential configured the module answers from a local corpus of seventy interlinked documents, so the whole surface is explorable offline.
- Highlights
- Two implementations
- Install
- Connecting
- Mock mode
- Command surface
- Naming rules
- Pipeline behaviour
- Safety
- When a cmdlet does not exist
- Building and testing
- How it is generated
- Documentation
- License
- Complete coverage, provably. 126 cmdlets over all 135 operations in Glean OpenAPI spec 0.9.0 — 91 Client API, 38 Indexing, 6 Custom Metadata — plus 11 core cmdlets. Coverage is enforced at build time: an operation with no cmdlet fails the build. See docs/SPEC_CONFORMANCE.md.
- Two implementations that are actually identical. A script module and a compiled binary module, generated from one contract file and checked against one Pester suite. A dedicated parity suite asserts they expose the same commands, parameters and parameter sets and return the same objects.
- Offline mock mode that is one coherent index. A URL from
Invoke-GleanSearchresolves inGet-GleanDocument, summarises to the same document, and appears as a real citation inSend-GleanChatMessage. The corpus file is shared byte-for-byte with glean-code-cli, and a parity test runs both implementations over the same queries and requires identical rankings. - Credentials that cannot leak. Resolved tokens are held outside the
connection object, so
Get-GleanConnection | ConvertTo-Json, a transcript, or an error dump carries a source label and a masked hint — never the value. - Four credential paths: API token, secure environment references, SecretManagement vaults, and browser SSO (OAuth 2.1 + PKCE).
- PowerShell conventions, enforced not assumed. Approved verbs, singular
nouns,
-WhatIfon everything that changes state, comment-based help with a runnable example on every command, PSScriptAnalyzer clean. Each of those is a test, not a claim — 1,831 assertions per implementation, at 78% coverage.
Glean |
Glean.Compiled |
|
|---|---|---|
| Form | Script module (.psm1) |
Binary module (.dll, net8.0) |
| Best for | Reading and modifying the source; no build step | Fast import; no source on disk |
| Import time | 118 ms | 15 ms |
| Commands | 137 functions + 2 aliases | 137 cmdlets + 2 aliases |
| Needs a build | no | yes (./build.ps1 -Task Build) |
Import time is the median of three cold processes on an M-series Mac with PowerShell 7.6 — the script module parses 152 files, the compiled one loads one assembly. It only matters if you import Glean in a short-lived script or a prompt function; for an interactive session either is imperceptible.
They expose the same surface and return the same objects. Install whichever suits your environment — but do not import both into one session, because they export the same command names.
Requires PowerShell 7.4 or later.
# from a local checkout
Import-Module ./src/Glean/Glean.psd1
# or the compiled twin, after ./build.ps1 -Task Build
Import-Module ./src/Glean.Compiled/bin/Release/net8.0/Glean.Compiled.psd1Take the guided offline tour — search, chat with citations, follow a citation to its document, summarise it, check permissions, run an agent, inspect the index:
./demo/Invoke-GleanTour.ps1# a secure reference: config.json holds the reference name, never the secret
$env:GLEAN_CLIENT_TOKEN = 'glean_...'
Connect-Glean -Instance acme -Token token.secure.client
# a SecretManagement vault
Connect-Glean -Instance acme -SecretName GleanProd -SecretVault Work
# prompt for the token without it reaching PSReadLine history
Connect-Glean -Instance acme -Credential (Get-Credential -UserName glean-prod)
# browser sign-in, OAuth 2.1 + PKCE
Connect-Glean -Instance acme -Sso-Instance takes an instance id (acme), a backend hostname
(acme-be.glean.com) or a full URL.
Then check what the session is really using:
Get-GleanConnection
Test-GleanConnectionTest-GleanConnection emits one object per check, so a script can gate on it:
if (Test-GleanConnection | Where-Object Status -eq 'Fail') { throw 'Glean is not usable' }| Reference | Resolves from | Stored on disk |
|---|---|---|
token.secure.client |
$env:GLEAN_CLIENT_TOKEN |
the reference name only |
token.secure.indexing |
$env:GLEAN_INDEXING_TOKEN |
the reference name only |
env:NAME |
$env:NAME |
the reference name only |
secret:NAME |
a SecretManagement vault | the reference name only |
| a literal token | — | never written; kept in memory |
The first two names are the same ones glean-code-cli uses, so a config written by either tool is understood by the other.
With no credential resolved, Connect-Glean -Mode Auto (the default) falls back
to Mock rather than firing an unauthenticated request that would only 401.
Mock mode is not a stub. Seventy documents across five faux datasources
(gdrive, confluence, jira, github, slack) cross-reference each other —
the checkout incident appears as a Jira ticket, a Slack war room, a Confluence
postmortem and the GitHub PR that fixed it.
Connect-Glean -Mock
Get-GleanMockCorpus # 70 documents, 8 people, 5 datasources
Get-GleanMockCorpus -Document -Datasource jira
Set-GleanMockCorpus -Path ./my-corpus.json # bring your ownThe corpus is shared with glean-code-cli. data/mock-corpus.json is exported
from the CLI's built-in corpus and loads back into it unchanged:
export GLEAN_MOCK_CORPUS=/path/to/glean-powershell/data/mock-corpus.json
python3 -m glean_code # the CLI now reads the same documentsThe ranking is a deliberate port, not a reimplementation: the same scoring
weights, tie-breaks, snippet selection and result envelope.
tests/Integration/MockParity.Tests.ps1 runs the Python implementation and this
one over the same queries and requires identical output — same documents, same
order, same snippets, same tracking tokens.
| Surface | Operations | Example cmdlets |
|---|---|---|
| Search, chat and summarize | 18 | Invoke-GleanSearch, Send-GleanChatMessage, Get-GleanChat, Get-GleanDocumentSummary |
| Agents and tools | 15 | Invoke-GleanAgent, Find-GleanAgent, Get-GleanTool, Invoke-GleanTool |
| Documents, people and entities | 6 | Get-GleanDocument, Get-GleanDocumentPermission, Get-GleanPerson, Get-GleanEntity |
| Knowledge management | 29 | New-GleanAnswer, Get-GleanCollection, New-GleanPin, Get-GleanShortcut, Set-GleanVerification |
| Governance and DLP | 14 | Get-GleanPolicy, New-GleanReport, Set-GleanDocumentVisibility, Save-GleanFindingExport |
| Datasources and auth | 6 | Get-GleanDatasourceConfiguration, Update-GleanDatasourceCredential, New-GleanAuthToken |
| Insights and activity | 3 | Get-GleanInsight, Send-GleanActivity, Send-GleanFeedback |
| Client API total | 91 | |
| Indexing — permissions and groups | 11 | Set-GleanIndexMembership, Sync-GleanIndexGroup, Set-GleanIndexDocumentPermission |
| Indexing — troubleshooting | 9 | Get-GleanIndexDebugStatus, Test-GleanIndexDocumentAccess, Get-GleanIndexDocumentCount |
| Indexing — people and teams | 7 | Set-GleanIndexEmployee, Sync-GleanIndexTeam, Start-GleanIndexEmployeeProcessing |
| Indexing — documents | 6 | Set-GleanIndexDocument, Sync-GleanIndexDocument, Start-GleanIndexDocumentProcessing |
| Indexing — datasources, shortcuts, auth | 5 | Set-GleanIndexDatasource, Sync-GleanIndexShortcut, Update-GleanIndexToken |
| Indexing API total | 38 | |
| Custom Metadata | 6 | Set-GleanMetadataSchema, Set-GleanDocumentMetadata, Submit-GleanDatasourceData |
| Spec total | 135 | covered by 126 cmdlets |
| Core, not from the spec | — | Connect-Glean, Test-GleanConnection, Invoke-GleanApi, Get-GleanApiOperation |
Fewer cmdlets than operations because a Get- cmdlet fronts both the list and
the fetch form of an endpoint pair — see
naming rules.
Find the cmdlet for any endpoint you know by path:
Get-GleanApiOperation -Path '*summarize*'
Get-GleanApiOperation | Group-Object Api | Select-Object Name, CountEvery command is Verb-GleanNoun with a verb from Get-Verb and a singular
noun. Beyond the obvious four:
| Verb | Means |
|---|---|
Sync |
bulk upload that makes the index match your source of truth |
Start |
begin asynchronous server-side processing |
Save |
write a returned file (CSV, image, attachment) to disk |
Send |
push data one way, expecting only an acknowledgement |
Find |
search a container |
Request |
begin an authorization flow |
Get- cmdlets list when given no identifier and fetch when given one, rather
than shipping a separate List- command (List is not an approved verb).
These rules are checked, not documented and hoped for:
tests/Unit/Naming.Tests.ps1 asserts every exported command satisfies each one.
Cmdlets emit the interesting part of a response, not the envelope:
Invoke-GleanSearch -Query 'incident' | Select-Object title, url # results, not {results, facets, cursor}
Invoke-GleanSearch -Query 'incident' -Raw # the whole envelopeWhen a response pages, the cursor is attached to each emitted object as
GleanCursor, so paging does not force -Raw.
Everything that changes state supports -WhatIf and -Confirm. Deletions and
bulk operations that replace a datasource's contents are ConfirmImpact High,
so they prompt by default.
Remove-GleanIndexDocument -Datasource gdrive -ObjectType Document -Id doc_1 -WhatIf
# What if: Performing the operation "Remove-GleanIndexDocument" on target "/api/index/v1/deletedocument (gdrive)".Invoke-GleanApi calls any path directly, through the same retry, error mapping
and credential selection as every generated cmdlet:
Invoke-GleanApi -Path /rest/api/v1/search -Body @{ query = 'pto policy'; pageSize = 3 }
Invoke-GleanApi -Path /api/index/v1/getdocumentcount -Body @{ datasource = 'gdrive' }The API family — and therefore which token signs the call — is inferred from the
path unless you pass -Api.
./build.ps1 # generate, build, analyze, test, docs, package
./build.ps1 -Task Test
./build.ps1 -Task Analyze
./build.ps1 -Task Test -SkipPython # skip generation and the Python parity suiteRun the suite against either implementation:
$env:GLEAN_TEST_MODULE = 'Compiled'
./build.ps1 -Task Test| Suite | What it pins down |
|---|---|
Unit/Naming |
verbs, nouns, help, ShouldProcess, manifest exports, source hygiene |
Unit/Http |
URI building, retry and backoff, error mapping, response unrolling |
Unit/Credential |
credential resolution, and that no token can reach the output |
Integration/Coverage |
every one of the 126 cmdlets actually runs, and honours -WhatIf |
Integration/MockParity |
this SDK and glean-code-cli rank the shared corpus identically |
Integration/Transport |
the live request path, driven through a local HTTP server: auth headers, retry, error mapping, downloads |
Integration/TwinParity |
the script and compiled modules are indistinguishable |
Integration/Resilience |
a corrupt config, a hand-edited corpus, an unresolvable credential, an unreachable host |
The cmdlets are not hand-written. Four tools turn the published spec into both modules, and each one fails the build rather than emitting something wrong:
client_rest.yaml + indexing.yaml
│ tools/extract_contract.py resolve $refs, flatten to one contract
▼
contract/glean-api.json 135 operations
│ tools/build_cmdlet_map.py name them; reject unapproved verbs,
▼ plural nouns, collisions, uncovered ops
contract/cmdlet-map.json 126 cmdlets
│ tools/build_surface.py resolve parameters, types, sets, help
▼
contract/cmdlet-surface.json 491 parameters
│
├── tools/generate_powershell.py ─► src/Glean/Public/*.ps1
└── tools/generate_csharp.py ─────► src/Glean.Compiled/Cmdlets/Generated/*.cs
Generated output is checked in so it is reviewable in a pull request, and CI fails if regenerating changes anything.
To refresh against a newer spec release:
mkdir -p build/spec && cd build/spec
curl -sSLO https://gleanwork.github.io/open-api/specs/final/client_rest.yaml
curl -sSLO https://gleanwork.github.io/open-api/specs/final/indexing.yaml
cd ../.. && ./build.ps1Any new operation fails build_cmdlet_map.py until it is given a name, which is
the point: coverage cannot silently regress.
- docs/SPEC_CONFORMANCE.md — coverage, naming decisions, and the twelve glean-code-cli divergences this SDK does not inherit
- docs/MOCK_MODE.md — the shared corpus, how parity with glean-code-cli is proven, and how to bring your own
- docs/AUTHENTICATION.md — the four credential paths, and why a token cannot reach your output
- docs/TESTING.md — what each suite pins down
- docs/cmdlets/ — reference page for all 137 commands
Get-Help about_Glean— the conceptual overviewGet-Help <command> -Full— every command, with examples
This SDK is a sibling of glean-code-cli, not a port of it. It shares the CLI's mock corpus, its secure-reference names and its banner, so the two read as one product — but the API layer is generated from Glean's spec rather than hand-written, which is why the CLI's twelve documented divergences do not appear here.
MIT. See LICENSE.
Not affiliated with or endorsed by Glean Technologies, Inc.