Managing task prompts
A task prompt is the text instructions sent to the agent. In MS Scope, every distinct task prompt the system has seen has its own record in the catalog. You don't pick a task prompt ID when submitting a request — you submit the prompt text inline and MS Scope de-duplicates by text server-side, linking your request to the existing record if it has seen the same text before.
Task prompts are also where prompt features live: feature detection runs against the task prompt record, not against each request, so it only happens once per distinct prompt.
Why they're separate
Section titled “Why they're separate”If each request stored an independent copy of the prompt text, every minor wording tweak would look unrelated. By giving each distinct prompt text its own record, Scope can:
- Group runs by the prompt they used, even across different criteria, profiles, and agents.
- Cache prompt-feature extraction so the same prompt isn't re-analyzed every submission.
- Surface re-use — see who's already benchmarking the same task.
Anatomy
Section titled “Anatomy”| Field | Type | Description |
| --- | --- | --- |
| _id | string | Stable identifier (assigned by Scope). |
| text | string | The full prompt text. Unique across the catalog. |
| features | object | Detected prompt features (populated by extraction). |
| featuresExtractedAt | string (ISO-8601) | Last extraction timestamp. |
| createdAt | string (ISO-8601) | Creation timestamp. |
How records are created
Section titled “How records are created”There are two ways a task prompt record comes into existence:
- As a side-effect of submitting a request. The first request that uses a given prompt text creates the record automatically.
- Explicitly, by creating one via the API or the Portal so you can trigger feature extraction or browse runs before submitting.
From the Portal
Section titled “From the Portal”Open Tasks in the navigation, click New task prompt, paste the text, save. The Portal opens the new record's detail page where you can trigger feature extraction.
From the REST API
Section titled “From the REST API”curl --request POST \ --url https://your-scope.example.com/api/v1/task-prompts \ --header 'Content-Type: application/json' \ --data '{ "text": "Create a Hello World Node.js / Express REST API." }'const url = 'https://your-scope.example.com/api/v1/task-prompts';const options = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{"text":"Create a Hello World Node.js / Express REST API."}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}import requests
url = "https://your-scope.example.com/api/v1/task-prompts"
payload = { "text": "Create a Hello World Node.js / Express REST API." }headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.json())package main
import ( "fmt" "strings" "net/http" "io")
func main() {
url := "https://your-scope.example.com/api/v1/task-prompts"
payload := strings.NewReader("{ \"text\": \"Create a Hello World Node.js / Express REST API.\" }")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close() body, _ := io.ReadAll(res.Body)
fmt.Println(res) fmt.Println(string(body))
}OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json");RequestBody body = RequestBody.create(mediaType, "{ \"text\": \"Create a Hello World Node.js / Express REST API.\" }");Request request = new Request.Builder() .url("https://your-scope.example.com/api/v1/task-prompts") .post(body) .addHeader("Content-Type", "application/json") .build();
Response response = client.newCall(request).execute();using System.Net.Http.Headers;var client = new HttpClient();var request = new HttpRequestMessage{ Method = HttpMethod.Post, RequestUri = new Uri("https://your-scope.example.com/api/v1/task-prompts"), Content = new StringContent("{ \"text\": \"Create a Hello World Node.js / Express REST API.\" }") { Headers = { ContentType = new MediaTypeHeaderValue("application/json") } }};using (var response = await client.SendAsync(request)){ response.EnsureSuccessStatusCode(); var body = await response.Content.ReadAsStringAsync(); Console.WriteLine(body);}Creation is idempotent by text — submitting the same text returns the existing record rather than creating a duplicate.
Browse and search
Section titled “Browse and search”The Tasks page lists every task prompt. Use the search box to find prompts by text. Each entry links to a detail page showing the prompt text, detected features, and runs that referenced it.
REST equivalents:
curl --request GET \ --url https://your-scope.example.com/api/v1/task-promptsconst url = 'https://your-scope.example.com/api/v1/task-prompts';const options = {method: 'GET'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}import requests
url = "https://your-scope.example.com/api/v1/task-prompts"
response = requests.get(url)
print(response.json())package main
import ( "fmt" "net/http" "io")
func main() {
url := "https://your-scope.example.com/api/v1/task-prompts"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close() body, _ := io.ReadAll(res.Body)
fmt.Println(res) fmt.Println(string(body))
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder() .url("https://your-scope.example.com/api/v1/task-prompts") .get() .build();
Response response = client.newCall(request).execute();using System.Net.Http.Headers;var client = new HttpClient();var request = new HttpRequestMessage{ Method = HttpMethod.Get, RequestUri = new Uri("https://your-scope.example.com/api/v1/task-prompts"),};using (var response = await client.SendAsync(request)){ response.EnsureSuccessStatusCode(); var body = await response.Content.ReadAsStringAsync(); Console.WriteLine(body);}curl --request GET \ --url https://your-scope.example.com/api/v1/task-prompts/%7Bid%7Dconst url = 'https://your-scope.example.com/api/v1/task-prompts/%7Bid%7D';const options = {method: 'GET'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}import requests
url = "https://your-scope.example.com/api/v1/task-prompts/%7Bid%7D"
response = requests.get(url)
print(response.json())package main
import ( "fmt" "net/http" "io")
func main() {
url := "https://your-scope.example.com/api/v1/task-prompts/%7Bid%7D"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close() body, _ := io.ReadAll(res.Body)
fmt.Println(res) fmt.Println(string(body))
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder() .url("https://your-scope.example.com/api/v1/task-prompts/%7Bid%7D") .get() .build();
Response response = client.newCall(request).execute();using System.Net.Http.Headers;var client = new HttpClient();var request = new HttpRequestMessage{ Method = HttpMethod.Get, RequestUri = new Uri("https://your-scope.example.com/api/v1/task-prompts/%7Bid%7D"),};using (var response = await client.SendAsync(request)){ response.EnsureSuccessStatusCode(); var body = await response.Content.ReadAsStringAsync(); Console.WriteLine(body);}Use a task prompt in a request
Section titled “Use a task prompt in a request”You don't pass a task prompt ID when submitting. Pass the prompt text inline:
{ "scenario": { "task": "Create a Hello World Node.js / Express REST API.", "criteria": ["c-hello-world-express"] }, "profileId": "p-550e8400-…"}Scope looks up (or creates) the matching task prompt record and links it to the new request. See Submitting requests (REST API).
Extract prompt features
Section titled “Extract prompt features”Feature extraction is on-demand, not automatic on creation. From the task prompt's detail page click Extract features, or:
curl --request POST \ --url https://your-scope.example.com/api/v1/task-prompts/%7Bid%7D/extract-featuresconst url = 'https://your-scope.example.com/api/v1/task-prompts/%7Bid%7D/extract-features';const options = {method: 'POST'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}import requests
url = "https://your-scope.example.com/api/v1/task-prompts/%7Bid%7D/extract-features"
response = requests.post(url)
print(response.json())package main
import ( "fmt" "net/http" "io")
func main() {
url := "https://your-scope.example.com/api/v1/task-prompts/%7Bid%7D/extract-features"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close() body, _ := io.ReadAll(res.Body)
fmt.Println(res) fmt.Println(string(body))
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder() .url("https://your-scope.example.com/api/v1/task-prompts/%7Bid%7D/extract-features") .post(null) .build();
Response response = client.newCall(request).execute();using System.Net.Http.Headers;var client = new HttpClient();var request = new HttpRequestMessage{ Method = HttpMethod.Post, RequestUri = new Uri("https://your-scope.example.com/api/v1/task-prompts/%7Bid%7D/extract-features"),};using (var response = await client.SendAsync(request)){ response.EnsureSuccessStatusCode(); var body = await response.Content.ReadAsStringAsync(); Console.WriteLine(body);}See Working with prompt features.
Soft-delete
Section titled “Soft-delete”Deleting a task prompt is a soft-delete — the record is hidden from list views, but past requests that referenced it still resolve.
curl --request DELETE \ --url https://your-scope.example.com/api/v1/task-prompts/%7Bid%7Dconst url = 'https://your-scope.example.com/api/v1/task-prompts/%7Bid%7D';const options = {method: 'DELETE'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}import requests
url = "https://your-scope.example.com/api/v1/task-prompts/%7Bid%7D"
response = requests.delete(url)
print(response.json())package main
import ( "fmt" "net/http" "io")
func main() {
url := "https://your-scope.example.com/api/v1/task-prompts/%7Bid%7D"
req, _ := http.NewRequest("DELETE", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close() body, _ := io.ReadAll(res.Body)
fmt.Println(res) fmt.Println(string(body))
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder() .url("https://your-scope.example.com/api/v1/task-prompts/%7Bid%7D") .delete(null) .build();
Response response = client.newCall(request).execute();using System.Net.Http.Headers;var client = new HttpClient();var request = new HttpRequestMessage{ Method = HttpMethod.Delete, RequestUri = new Uri("https://your-scope.example.com/api/v1/task-prompts/%7Bid%7D"),};using (var response = await client.SendAsync(request)){ response.EnsureSuccessStatusCode(); var body = await response.Content.ReadAsStringAsync(); Console.WriteLine(body);}- Treat the catalog as shared. Don't tweak wording on every submission — each unique string creates a new record and splits prompt-feature data.
- Don't bake configuration into the prompt text. Things like the model name, the worker, or the criteria belong on the request and the profile, not in the prompt.
- Wait for extraction once, then move on. Feature extraction
results are cached on the task prompt; you only need to re-run it
with
?force=truewhen the catalog of features has changed and you want to re-evaluate.