Skip to main content

selectArtefacts

selectArtefacts(by: ...) is the slim, repo-scoped DevQL GraphQL selector for agent-oriented code analysis.

It lets you:

  • select a current set of artefacts once
  • ask for one aggregate overview across all supported categories
  • drill into one category only when that overview suggests it is worth the tokens

This is the intended shape for tool-using agents.

Availability

selectArtefacts(by: ...) is available on the slim GraphQL surface only.

  • Raw GraphQL: supported
  • Slim /devql SDL and Explorer: supported
  • DevQL DSL compiler: supported for one explicit terminal stage at a time
  • DevQL DSL aggregate selectArtefacts(...)->overview(): not supported yet
  • Global/full GraphQL surface: not supported

Selector Modes

Exactly one selector mode must be used.

By symbolFqn

{
selectArtefacts(by: { symbolFqn: "rust-app/src/main.rs::main" }) {
count
artefacts {
path
symbolFqn
summary
embeddingRepresentations
}
}
}

This usually resolves to 0..1 logical artefacts, but callers should treat the result as a set.

{
selectArtefacts(by: { search: "payLater()" }) {
count
artefacts {
path
symbolFqn
summary
embeddingRepresentations
}
}
}

search runs two internal lanes and returns one flat artefact list:

  • up to 5 fuzzy symbol-name matches, including typo-tolerant requests such as payLater() or payLatr()
  • up to 5 embedding-backed conceptual matches across identity, code, and summary representations

Fuzzy hits are returned first, embedding-only hits follow, weak matches are dropped, and score remains optional debug output rather than part of the default contract.

By path and lines

{
selectArtefacts(by: { path: "rust-app/src/main.rs", lines: { start: 6, end: 10 } }) {
count
artefacts {
path
symbolFqn
summary
embeddingRepresentations
startLine
endLine
}
}
}

This resolves all current artefacts in that file whose ranges overlap the selected line span.

By path

{
selectArtefacts(by: { path: "rust-app/src/main.rs" }) {
count
artefacts {
path
symbolFqn
summary
embeddingRepresentations
}
}
}

This resolves all current artefacts in the file.

Validation Rules

  • symbolFqn cannot be combined with search, path, or lines
  • search cannot be combined with symbolFqn, path, or lines
  • search must be non-empty
  • lines requires path
  • empty selectors are rejected
  • selector paths are resolved relative to the slim request scope, including project-scoped slim requests
  • selection is current-state only in v1; asOf(...) is not part of this surface

Selection Shape

selectArtefacts(by: ...) returns one ArtefactSelection object representing the selected set.

type ArtefactSelection {
count: Int!
overview: JSON!
artefacts(first: Int! = 20): [Artefact!]!
checkpoints(agent: String, since: DateTime): CheckpointStageResult!
dependencies(kind: EdgeKind, direction: DepsDirection! = BOTH, includeUnresolved: Boolean! = true): DependencyStageResult!
codeMatches(relationKind: String, minScore: Float): CloneStageResult!
tests(minConfidence: Float, linkageSource: String): TestsStageResult!
historicalContext(agent: String, since: DateTime, evidenceKind: HistoricalEvidenceKind): HistoricalContextStageResult!
contextGuidance(agent: String, since: DateTime, evidenceKind: HistoricalEvidenceKind, category: ContextGuidanceCategory, kind: String): ContextGuidanceStageResult!
}

Use:

  • count to know how many artefacts matched
  • artefacts(...) when you want to inspect the matched set itself
  • each returned Artefact can expose semantic summary plus embeddingRepresentations
  • overview when you want one compact answer across all supported categories
  • stage fields when you want one category in more detail

Aggregate overview

The selection-level overview field returns a JSON object with one entry per supported category.

{
selectArtefacts(by: { path: "rust-app/src/main.rs", lines: { start: 6, end: 10 } }) {
overview
}
}

Representative shape:

{
"selectedArtefactCount": 2,
"checkpoints": {
"overview": {
"totalCount": 0,
"latestAt": null,
"agents": []
},
"schema": null
},
"codeMatches": {
"overview": {
"counts": {
"total": 2,
"similar_implementation": 2
},
"expandHint": {
"intent": "Inspect code matches",
"template": "bitloops devql query '{ selectArtefacts(by: ...) { codeMatches(relationKind: <KIND>) { items(first: 20) { ... } } } }'",
"parameters": [
{
"name": "kind",
"intent": "Choose which relation kind to inspect",
"supportedValues": [
"exact_duplicate",
"similar_implementation",
"shared_logic_candidate",
"diverged_implementation",
"weak_clone_candidate"
]
}
]
}
},
"expandHint": {
"intent": "Inspect code matches",
"template": "bitloops devql query '{ selectArtefacts(by: ...) { codeMatches(relationKind: <KIND>) { items(first: 20) { ... } } } }'",
"parameters": [
{
"name": "kind",
"intent": "Choose which relation kind to inspect",
"supportedValues": [
"exact_duplicate",
"similar_implementation",
"shared_logic_candidate",
"diverged_implementation",
"weak_clone_candidate"
]
}
]
},
"schema": "type ArtefactSelection { ... }"
},
"dependencies": {
"overview": {
"dependencies": {
"selectedArtefact": 2,
"total": 2,
"incoming": 0,
"outgoing": 2,
"kindCounts": {
"calls": 2,
"exports": 0,
"extends": 0,
"implements": 0,
"imports": 0,
"references": 0
}
}
},
"expandHint": {
"intent": "Use direction to filter dependencies by flow relative to the selected artefacts: incoming maps to IN and outgoing maps to OUT. Use kind to filter dependencies by relationship type: kindCounts.calls maps to CALLS, kindCounts.imports maps to IMPORTS and so on.",
"template": "Direction example: bitloops devql query '{ selectArtefacts(...) { dependencies(direction: IN) { items(first: 50) { edgeKind fromArtefact { symbolFqn path startLine endLine } toArtefact { symbolFqn path startLine endLine } toSymbolRef } } } }'",
"parameters": [
{
"name": "direction",
"intent": "Choose dependency flow relative to the selected artefacts",
"supportedValues": ["IN", "OUT"]
},
{
"name": "kind",
"intent": "Choose dependency relationship type",
"supportedValues": ["CALLS", "EXPORTS", "EXTENDS", "IMPLEMENTS", "IMPORTS", "REFERENCES"]
}
]
},
"schema": "type ArtefactSelection { ... }"
},
"tests": {
"overview": {
"selectedArtefactCount": 2,
"matchedArtefactCount": 2,
"totalCoveringTests": 2,
"expandHint": {
"intent": "Inspect concrete covering tests for selected artefacts",
"template": "bitloops devql query '{ selectArtefacts(by: { symbolFqn: \"<symbol-fqn>\" }) { tests { overview items(first: 20) { coveringTests { testName suiteName filePath startLine endLine } } } } }'"
}
},
"schema": "type ArtefactSelection { ... }"
},
"historicalContext": {
"overview": {
"totalCount": 1,
"checkpointCount": 1,
"sessionCount": 1,
"turnCount": 1,
"evidenceCounts": {
"symbolProvenance": 1,
"fileRelation": 1,
"lineOverlap": 0
}
},
"schema": "type ArtefactSelection { ... }"
},
"contextGuidance": {
"overview": {
"totalCount": 1,
"categoryCounts": {
"DECISION": 1
},
"kindCounts": {
"architectural_boundary": 1
}
},
"schema": "type ArtefactSelection { ... }"
}
}

Notes:

  • overview is stage-owned JSON, not stringified JSON
  • schema is null when that stage has no results
  • schema is included in the aggregate response so an agent can discover the drill-down surface without re-querying first
  • tests.overview.expandHint is always included when tests overview is requested and points to the concrete coveringTests drill-down query
  • overview.dependencies.expandHint maps the dependency buckets back to concrete dependencies(direction:..., kind:...) follow-up queries
  • overview.dependencies.expandHint is omitted when no dependencies match the selected artefacts
  • codeMatches overviews always include counts.total
  • expandHint is omitted when counts.total is 0

Stage Results

Each category field returns a typed stage result object.

type CheckpointStageResult {
overview: JSON!
schema: String
items(first: Int! = 20): [Checkpoint!]!
}

The other stage result types follow the same pattern:

  • CloneStageResult
  • DependencyStageResult
  • TestsStageResult
  • HistoricalContextStageResult
  • ContextGuidanceStageResult

CloneStageResult and DependencyStageResult both expose a typed expandHint field:

type CloneStageResult {
overview: JSON!
expandHint: CloneExpandHint
schema: String
items(first: Int! = 20): [Clone!]!
}

type DependencyStageResult {
overview: JSON!
expandHint: DependencyExpandHint
schema: String
items(first: Int! = 20): [DependencyEdge!]!
}

Use them like this:

{
selectArtefacts(by: { path: "rust-app/src/main.rs" }) {
codeMatches {
overview
expandHint {
intent
template
parameters {
name
intent
supportedValues
}
}
items(first: 10) {
relationKind
score
}
}
dependencies {
overview
expandHint {
intent
template
parameters {
name
intent
supportedValues
}
}
schema
items(first: 10) {
id
edgeKind
toSymbolRef
}
}
}
}

This is the normal escalation path:

  1. Ask for overview
  2. Decide which category matters
  3. For dependencies, use the typed stage field expandHint, or the aggregate overview.dependencies.expandHint when you are still in overview-only mode
  4. Read schema only if needed
  5. Query items(first: ...) for typed detail rows

Agent Hook Guidance

Bitloops now treats the DevQL hook as guidance-gated. When the Bitloops-managed using-devql guidance surface is enabled for an agent, Bitloops installs the repo-local DevQL guidance surface and emits direct startup guidance for that surface. When that guidance is disabled, Bitloops emits no DevQL guidance at all.

The current enforcement contract is:

  • Claude Code and Codex regain targeted prompt-time reinforcement in addition to the repo-local surface
  • Cursor remains session-start plus rule-based
  • other supported agents follow the same repo-local surface contract when their DevQL Guidance is enabled

The guidance follows the same workflow documented here:

  1. Start with selectArtefacts(by: ...) { overview }
  2. Read stage schema only when the overview says a drill-down is worth it
  3. Query items(first: ...) on the relevant stage for typed rows
  4. Use bitloops devql schema or bitloops devql schema --global when the full SDL is needed

This guidance is guidance only. It does not execute DevQL automatically or attach live query results to the turn.

Category Overviews

Current category coverage:

CategoryOverview intentDetail type
checkpointsCount, latest timestamp, participating agentsCheckpoint
codeMatchesTotal count, grouped relation kinds, max scoreClone
testsMatched artefact count, total covering tests, drill-down hintTestHarnessTestsResult
dependenciesNested counts plus a default drill-down hint for direction / kind follow-up queriesDependencyEdge
historicalContextPrior checkpoints, sessions, turns, prompts, transcript previews, tool events, and file relations tied to the selected artefactsHistoricalContextItem
contextGuidanceDistilled future-session guidance, grouped by durable categories such as decisions, constraints, risks, and verification requirementsContextGuidanceItem

Stage Arguments

checkpoints

checkpoints(agent: String, since: DateTime)

codeMatches

codeMatches(relationKind: String, minScore: Float)

dependencies

dependencies(kind: EdgeKind, direction: DepsDirection! = BOTH, includeUnresolved: Boolean! = false)

Defaults for selection stages:

  • direction = BOTH
  • includeUnresolved = false

tests

tests(minConfidence: Float, linkageSource: String)

historicalContext

historicalContext(agent: String, since: DateTime, evidenceKind: HistoricalEvidenceKind)

contextGuidance

contextGuidance(agent: String, since: DateTime, evidenceKind: HistoricalEvidenceKind, category: ContextGuidanceCategory, kind: String)

Use contextGuidance when prior history or linked knowledge has been distilled into durable guidance for the selected artefact. A typical architectural-decision use case is making a past file-level decision visible before a future edit:

{
selectArtefacts(by: { path: "src/target.ts" }) {
contextGuidance(category: DECISION, kind: "architectural_boundary") {
overview
items(first: 5) {
category
kind
guidance
evidenceExcerpt
sources {
checkpointId
turnId
}
}
}
}
}

That lets an agent see guidance such as “keep this file as the boundary for target result calculation” before making the next code change.

DevQL DSL Form

The DevQL DSL supports selectArtefacts(...) with flat selector args:

selectArtefacts(symbol_fqn:"rust-app/src/main.rs::main")->checkpoints()
selectArtefacts(search:"payLater()")->checkpoints()
selectArtefacts(path:"rust-app/src/main.rs",lines:6..10)->deps()
selectArtefacts(path:"rust-app/src/main.rs")->tests(min_confidence:0.8)
selectArtefacts(path:"rust-app/src/main.rs")->historicalContext(evidence_kind:"file_relation")
selectArtefacts(path:"rust-app/src/main.rs")->contextGuidance(category:"decision",kind:"architectural_boundary")

Current DSL limitations:

  • compiles only against the slim endpoint
  • supports one explicit terminal stage at a time
  • defaults to selecting overview
  • ->select(overview,schema) is supported for the chosen stage
  • the DSL stage name remains deps(), but it compiles to the raw GraphQL dependencies(...) field on selectArtefacts
  • aggregate selectArtefacts { overview } is not yet available through the DSL

For tool-using agents, the lowest-error pattern is:

  1. Resolve the artefact set with selectArtefacts(by: ...)
  2. Ask for aggregate overview
  3. Choose the category worth expanding
  4. Query that category’s items(first: ...)

That keeps the default call compact while still allowing full typed detail on demand.