qdoc-agent 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +230 -0
- package/bin/qdoc.js +12 -0
- package/install.js +74 -0
- package/package.json +26 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ibrhr
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# qdoc — Agent for Agents
|
|
2
|
+
|
|
3
|
+
Documentation research for AI coding agents. No trial-and-error. No wasted tokens. One call, one answer.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
$ qdoc go "how do generics work in Go"
|
|
7
|
+
|
|
8
|
+
● Thinking ···
|
|
9
|
+
● Calling gpt-5.5 on openai
|
|
10
|
+
▶ READ: tutorial/generics
|
|
11
|
+
▶ READ: effective_go
|
|
12
|
+
▶ READ: go1.24
|
|
13
|
+
|
|
14
|
+
## Generics in Go
|
|
15
|
+
|
|
16
|
+
Type parameters enable...
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Why qdoc?
|
|
22
|
+
|
|
23
|
+
AI coding agents waste tokens when researching documentation. The typical agent loop:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
Agent: searches docs index → finds 200+ links
|
|
27
|
+
Agent: fetches 5 pages, none are right
|
|
28
|
+
Agent: tries 5 more, close but incomplete
|
|
29
|
+
Agent: one more round, finally gets it
|
|
30
|
+
Agent: synthesizes answer
|
|
31
|
+
|
|
32
|
+
Total: ~10 page fetches, ~40% irrelevant content, 3 LLM rounds
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**qdoc replaces this with a one-shot LLM call:**
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
qdoc: fetches doc index (1 HTTP call)
|
|
39
|
+
qdoc: passes index → query to LLM (1 inference)
|
|
40
|
+
LLM: returns "read these 3 specific pages"
|
|
41
|
+
qdoc: fetches them in parallel (3 HTTP calls)
|
|
42
|
+
qdoc: if needed, asks LLM for one more round (up to 5 turns)
|
|
43
|
+
LLM: synthesizes final answer with citations
|
|
44
|
+
|
|
45
|
+
Total: 1-5 page fetches, 100% LLM-selected relevance, 1-2 LLM rounds
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The difference compounds: an agent making 10 doc queries per session saves 50+ unnecessary page fetches and 15-20 redundant LLM rounds.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Quick start
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Linux, macOS (shell)
|
|
56
|
+
curl -fsSL https://qdoc.ibrhr.dev/install.sh | bash
|
|
57
|
+
|
|
58
|
+
# Any platform (npm)
|
|
59
|
+
npm install -g qdoc-agent
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
qdoc set key openai # prompts for your API key (input hidden)
|
|
64
|
+
qdoc go "generics tutorial" # ask your first question
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Usage
|
|
70
|
+
|
|
71
|
+
### As a human (interactive TUI)
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
qdoc go "how does context work?"
|
|
75
|
+
qdoc fastapi "dependency injection patterns"
|
|
76
|
+
qdoc ./my-docs "deployment guide"
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Built with Bubble Tea v2. Live streaming, scrollable output, interactive provider/model pickers.
|
|
80
|
+
|
|
81
|
+
### As an agent (headless)
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Markdown to stdout — agent parses directly
|
|
85
|
+
qdoc --no-tui go "error wrapping with fmt.Errorf"
|
|
86
|
+
|
|
87
|
+
# Structured JSON — for programmatic consumption
|
|
88
|
+
qdoc --json go "generics constraints" | jq '.answer'
|
|
89
|
+
|
|
90
|
+
# In CI pipelines
|
|
91
|
+
qdoc --no-tui --json go "release notes for Go 1.24" > result.json
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Integration
|
|
95
|
+
|
|
96
|
+
Copy [`skill.md`](skill.md) to your agent's skills directory:
|
|
97
|
+
|
|
98
|
+
| Agent | Path |
|
|
99
|
+
|-------|------|
|
|
100
|
+
| **opencode** | `~/.agents/skills/qdoc/SKILL.md` |
|
|
101
|
+
| **Claude Code** | `~/.claude/skills/qdoc.md` |
|
|
102
|
+
| **Cursor** | Add as custom instruction |
|
|
103
|
+
|
|
104
|
+
Or instruct any agent manually:
|
|
105
|
+
|
|
106
|
+
> When you need documentation about a framework or library, run `qdoc --no-tui <source> <query>`. Available sources: go, fastapi, or any local docs directory.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Providers
|
|
111
|
+
|
|
112
|
+
qdoc uses any OpenAI-compatible API.
|
|
113
|
+
|
|
114
|
+
| Provider | Default Model | Models Available |
|
|
115
|
+
|----------|--------------|-----------------|
|
|
116
|
+
| `openai` | `gpt-5.5` | gpt-5.5, gpt-5.5-pro, gpt-5.4, gpt-5.4-pro, gpt-5.4-mini, gpt-5.4-nano |
|
|
117
|
+
| `deepseek` | `deepseek-v4-flash` | deepseek-v4-flash, deepseek-v4-pro |
|
|
118
|
+
| `opencode-zen` | `gpt-5.4-mini` | GPT 5.5/5.4, Claude Opus 4.x, Claude Sonnet 4.x, Claude Haiku 4.5, Gemini 3.x, Qwen, MiniMax, GLM, Kimi, DeepSeek, Nemotron |
|
|
119
|
+
| `opencode-go` | `deepseek-v4-flash` | Qwen, MiniMax, GLM, Kimi, DeepSeek, MiMo (low-cost coding models) |
|
|
120
|
+
|
|
121
|
+
Set a provider interactively (`qdoc provider`), via config, or with env vars: `OPENAI_API_KEY`, `DEEPSEEK_API_KEY`, `OPENCODE_ZEN_API_KEY`, `OPENCODE_GO_API_KEY`.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Documentation sources
|
|
126
|
+
|
|
127
|
+
| Source | Description |
|
|
128
|
+
|--------|------------|
|
|
129
|
+
| `go` | Go standard library, toolchain, modules, tutorials — [go.dev/doc](https://go.dev/doc) |
|
|
130
|
+
| `fastapi` | FastAPI framework — [fastapi.tiangolo.com](https://fastapi.tiangolo.com) |
|
|
131
|
+
| `./path` | Any local directory of markdown, HTML, RST, or AsciiDoc files |
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
qdoc sources # list all available sources
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Configuration
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
// ~/.config/qdoc/config.json
|
|
143
|
+
{
|
|
144
|
+
"provider": "openai",
|
|
145
|
+
"keys": { "openai": "sk-..." },
|
|
146
|
+
"models": { "openai": "gpt-5.5" }
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Resolution order: `QDOC_*` environment variables → config file → built-in defaults.
|
|
151
|
+
|
|
152
|
+
| Variable | Overrides |
|
|
153
|
+
|----------|----------|
|
|
154
|
+
| `QDOC_PROVIDER` | Active provider |
|
|
155
|
+
| `QDOC_MODEL` | Active model |
|
|
156
|
+
| `QDOC_BASE_URL` | API base URL |
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Commands
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
qdoc go "query" # query Go docs
|
|
164
|
+
qdoc fastapi "query" # query FastAPI docs
|
|
165
|
+
qdoc ./my-docs "query" # query local docs directory
|
|
166
|
+
|
|
167
|
+
qdoc provider # interactive provider picker (TUI)
|
|
168
|
+
qdoc model # interactive model picker (TUI)
|
|
169
|
+
qdoc set key openai # save an API key (prompts securely)
|
|
170
|
+
qdoc set key openai sk-... # save an API key (inline)
|
|
171
|
+
qdoc set provider openai # switch default provider
|
|
172
|
+
qdoc set model openai gpt-5.5 # set model for a provider
|
|
173
|
+
|
|
174
|
+
qdoc status # show current config
|
|
175
|
+
qdoc providers # list providers + key status
|
|
176
|
+
qdoc sources # list documentation sources
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Install
|
|
182
|
+
|
|
183
|
+
### Shell script (Linux, macOS)
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
curl -fsSL https://qdoc.ibrhr.dev/install.sh | bash
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Installs to `~/.qdoc/bin` (no sudo). Adds itself to your shell config. Options:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
curl -fsSL ... | bash -s -- --version 0.1.2 # specific version
|
|
193
|
+
curl -fsSL ... | bash -s -- --no-modify-path # don't touch shell config
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### npm (all platforms)
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
npm install -g qdoc-agent
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Manual download
|
|
203
|
+
|
|
204
|
+
Binaries for every platform on [GitHub Releases](https://github.com/ibrhr/qdoc/releases/latest).
|
|
205
|
+
|
|
206
|
+
### From source
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
git clone https://github.com/ibrhr/qdoc.git
|
|
210
|
+
cd qdoc
|
|
211
|
+
go build -ldflags "-X main.version=$(git describe --tags) -X main.commit=$(git rev-parse --short HEAD)" -o qdoc .
|
|
212
|
+
mv qdoc ~/.local/bin/
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Requires Go 1.26+.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Verify
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
qdoc --version
|
|
223
|
+
# qdoc 0.1.2 (abc1234)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## License
|
|
229
|
+
|
|
230
|
+
MIT
|
package/bin/qdoc.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { execFileSync } = require("child_process");
|
|
3
|
+
const { join } = require("path");
|
|
4
|
+
|
|
5
|
+
const ext = process.platform === "win32" ? ".exe" : "";
|
|
6
|
+
const bin = join(__dirname, "..", "qdoc_bin" + ext);
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
execFileSync(bin, process.argv.slice(2), { stdio: "inherit" });
|
|
10
|
+
} catch (err) {
|
|
11
|
+
process.exit(err.status || 1);
|
|
12
|
+
}
|
package/install.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const { execSync } = require("child_process");
|
|
2
|
+
const { existsSync, renameSync, mkdirSync, rmSync, writeFileSync } = require("fs");
|
|
3
|
+
const { join } = require("path");
|
|
4
|
+
const https = require("https");
|
|
5
|
+
|
|
6
|
+
const REPO = "ibrhr/qdoc";
|
|
7
|
+
|
|
8
|
+
function mapPlatform() {
|
|
9
|
+
const goos = { linux: "linux", darwin: "darwin", win32: "windows" }[process.platform];
|
|
10
|
+
const goarch = { x64: "amd64", arm64: "arm64" }[process.arch];
|
|
11
|
+
if (!goos || !goarch) throw new Error(`Unsupported: ${process.platform}/${process.arch}`);
|
|
12
|
+
return `${goos}_${goarch}`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function fetch(url) {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
https.get(url, (res) => {
|
|
18
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
19
|
+
https.get(res.headers.location, (rr) => {
|
|
20
|
+
const c = []; rr.on("data", (d) => c.push(d));
|
|
21
|
+
rr.on("end", () => resolve(Buffer.concat(c)));
|
|
22
|
+
rr.on("error", reject);
|
|
23
|
+
});
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const c = []; res.on("data", (d) => c.push(d));
|
|
27
|
+
res.on("end", () => resolve(Buffer.concat(c)));
|
|
28
|
+
res.on("error", reject);
|
|
29
|
+
}).on("error", reject);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function main() {
|
|
34
|
+
const pkgDir = join(__dirname);
|
|
35
|
+
const ext = process.platform === "win32" ? ".exe" : "";
|
|
36
|
+
const dest = join(pkgDir, "qdoc_bin" + ext);
|
|
37
|
+
|
|
38
|
+
if (existsSync(dest)) return;
|
|
39
|
+
|
|
40
|
+
const platform = mapPlatform();
|
|
41
|
+
const base = `https://github.com/${REPO}/releases/latest/download/qdoc_${platform}`;
|
|
42
|
+
const url = process.platform === "win32" ? `${base}.zip` : `${base}.tar.gz`;
|
|
43
|
+
|
|
44
|
+
process.stderr.write(`qdoc: downloading ${url}\n`);
|
|
45
|
+
const buf = await fetch(url);
|
|
46
|
+
|
|
47
|
+
const tmp = join(pkgDir, ".qdoc_tmp");
|
|
48
|
+
mkdirSync(tmp, { recursive: true });
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
if (process.platform === "win32") {
|
|
52
|
+
writeFileSync(join(tmp, "qdoc.zip"), buf);
|
|
53
|
+
execSync(`tar -xf qdoc.zip`, { cwd: tmp, stdio: "ignore" });
|
|
54
|
+
} else {
|
|
55
|
+
writeFileSync(join(tmp, "qdoc.tar.gz"), buf);
|
|
56
|
+
execSync(`tar xzf qdoc.tar.gz`, { cwd: tmp, stdio: "ignore" });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const src = join(tmp, "qdoc" + ext);
|
|
60
|
+
if (!existsSync(src)) throw new Error("binary not found in archive");
|
|
61
|
+
renameSync(src, dest);
|
|
62
|
+
} finally {
|
|
63
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (process.platform !== "win32") {
|
|
67
|
+
execSync(`chmod +x "${dest}"`, { stdio: "ignore" });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
main().catch((err) => {
|
|
72
|
+
console.error("qdoc install failed:", err.message);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "qdoc-agent",
|
|
3
|
+
"version": "0.1.5",
|
|
4
|
+
"description": "Agent for Agents — documentation research for AI coding agents. One call, one answer. No trial-and-error. No wasted tokens.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": "github:ibrhr/qdoc",
|
|
7
|
+
"bin": {
|
|
8
|
+
"qdoc": "bin/qdoc.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"postinstall": "node install.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"install.js",
|
|
15
|
+
"bin/qdoc.js"
|
|
16
|
+
],
|
|
17
|
+
"os": [
|
|
18
|
+
"linux",
|
|
19
|
+
"darwin",
|
|
20
|
+
"win32"
|
|
21
|
+
],
|
|
22
|
+
"cpu": [
|
|
23
|
+
"x64",
|
|
24
|
+
"arm64"
|
|
25
|
+
]
|
|
26
|
+
}
|