一键导入
messages
Add new safe-output message types and wire validation/rendering.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Add new safe-output message types and wire validation/rendering.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | messages |
| description | Add new safe-output message types and wire validation/rendering. |
Use this guide to add a new message type to the safe-output messages system so it works in frontmatter, compiler parsing, JavaScript, and bundling.
The messages system lets workflow authors customize safe-output messages. Message flow:
Add the new message field to pkg/parser/schemas/main_workflow_schema.json in the messages object:
{
"messages": {
"properties": {
"my-new-message": {
"type": "string",
"description": "Description of when this message is used. Available placeholders: {placeholder1}, {placeholder2}.",
"examples": [
"Example message with {placeholder1}"
]
}
}
}
}
Key points:
kebab-case for the YAML field name (e.g., my-new-message)make build after changes (schema is embedded in binary)Add the new field to SafeOutputMessagesConfig in pkg/workflow/compiler.go:
type SafeOutputMessagesConfig struct {
// ... existing fields ...
MyNewMessage string `yaml:"my-new-message,omitempty" json:"myNewMessage,omitempty"` // Description of the message
}
Key points:
CamelCase for Go field namekebab-case for YAML tag (matches frontmatter)camelCase for JSON tag (used in JavaScript)omitempty to both tagsIf needed, update the parser in pkg/workflow/safe_outputs.go:
func parseMessagesConfig(messagesMap map[string]any) *SafeOutputMessagesConfig {
config := &SafeOutputMessagesConfig{}
// ... existing parsing ...
if myNewMessage, ok := messagesMap["my-new-message"].(string); ok {
config.MyNewMessage = myNewMessage
}
return config
}
Note: The parser uses reflection for most fields, so this step may not be needed for simple string fields.
Create a new file pkg/workflow/js/messages_my_new.cjs:
// @ts-check
/// <reference types="@actions/github-script" />
/**
* My New Message Module
*
* This module provides the my-new-message generation
* for [describe when it's used].
*/
const { getMessages, renderTemplate, toSnakeCase } = require("./messages_core.cjs");
/**
* @typedef {Object} MyNewMessageContext
* @property {string} placeholder1 - Description of placeholder1
* @property {string} placeholder2 - Description of placeholder2
*/
/**
* Get the my-new-message, using custom template if configured.
* @param {MyNewMessageContext} ctx - Context for message generation
* @returns {string} The generated message
*/
function getMyNewMessage(ctx) {
const messages = getMessages();
// Create context with both camelCase and snake_case keys
const templateContext = toSnakeCase(ctx);
// Default message template
const defaultMessage = "Default message with {placeholder1} and {placeholder2}";
// Use custom message if configured
return messages?.myNewMessage
? renderTemplate(messages.myNewMessage, templateContext)
: renderTemplate(defaultMessage, templateContext);
}
module.exports = {
getMyNewMessage,
};
Key points:
messages_<category>.cjs (flat structure, not subfolder)./messages_core.cjs for shared utilitiesCreate pkg/workflow/js/messages_my_new.test.cjs:
import { describe, it, expect, beforeEach, vi } from "vitest";
// Mock core global
const mockCore = {
warning: vi.fn(),
};
global.core = mockCore;
describe("getMyNewMessage", () => {
beforeEach(() => {
vi.clearAllMocks();
delete process.env.GH_AW_SAFE_OUTPUT_MESSAGES;
});
it("should return default message when no custom message configured", async () => {
const { getMyNewMessage } = await import("./messages_my_new.cjs");
const result = getMyNewMessage({
placeholder1: "value1",
placeholder2: "value2",
});
expect(result).toBe("Default message with value1 and value2");
});
it("should use custom message when configured", async () => {
process.env.GH_AW_SAFE_OUTPUT_MESSAGES = JSON.stringify({
myNewMessage: "Custom: {placeholder1}",
});
const { getMyNewMessage } = await import("./messages_my_new.cjs");
const result = getMyNewMessage({
placeholder1: "test",
placeholder2: "ignored",
});
expect(result).toContain("Custom: test");
});
});
Run tests with make test-js.
Add the new property to the SafeOutputMessages typedef in pkg/workflow/js/messages_core.cjs:
/**
* @typedef {Object} SafeOutputMessages
* @property {string} [footer] - Custom footer message template
* // ... existing properties ...
* @property {string} [myNewMessage] - Custom my-new-message template
*/
Also update the getMessages() function return object:
return {
footer: rawMessages.footer,
// ... existing fields ...
myNewMessage: rawMessages.myNewMessage,
};
Add the re-export to pkg/workflow/js/messages.cjs:
// Re-export my new messages
const { getMyNewMessage } = require("./messages_my_new.cjs");
module.exports = {
// ... existing exports ...
getMyNewMessage,
};
Add to pkg/workflow/js.go:
//go:embed js/messages_my_new.cjs
var messagesMyNewScript string
Add to GetJavaScriptSources():
func GetJavaScriptSources() map[string]string {
return map[string]string{
// ... existing entries ...
"messages_my_new.cjs": messagesMyNewScript,
}
}
Import directly from the specific module in scripts that need it:
const { getMyNewMessage } = require("./messages_my_new.cjs");
// Use the message
const message = getMyNewMessage({
placeholder1: actualValue1,
placeholder2: actualValue2,
});
Update scratchpad/safe-output-messages.md:
Update the Message Module Architecture table:
| Module | Purpose | Exported Functions |
|--------|---------|-------------------|
| `messages_my_new.cjs` | My new message description | `getMyNewMessage` |
Before committing:
pkg/parser/schemas/main_workflow_schema.jsonpkg/workflow/compiler.gopkg/workflow/safe_outputs.gopkg/workflow/js/messages_my_new.cjspkg/workflow/js/messages_my_new.test.cjsmessages_core.cjsmessages.cjsjs.goGetJavaScriptSources() mapscratchpad/safe-output-messages.mdmake test-jsmake buildmake lint| File | Purpose | Changes Needed |
|---|---|---|
pkg/parser/schemas/main_workflow_schema.json | JSON Schema | Add field definition |
pkg/workflow/compiler.go | Go struct | Add struct field |
pkg/workflow/safe_outputs.go | Parser | Add parsing logic (if needed) |
pkg/workflow/js/messages_my_new.cjs | JavaScript module | Create new file |
pkg/workflow/js/messages_my_new.test.cjs | Tests | Create new file |
pkg/workflow/js/messages_core.cjs | Core utilities | Update typedef |
pkg/workflow/js/messages.cjs | Barrel file | Add re-export |
pkg/workflow/js.go | Go embeddings | Add embed directive |
scratchpad/safe-output-messages.md | Documentation | Document new message |
close-older-discussion MessageThis message type was added following this process:
close-older-discussion field with placeholders {new_discussion_number}, {new_discussion_url}, {workflow_name}, {run_url}CloseOlderDiscussion string fieldmessages_close_discussion.cjs with getCloseOlderDiscussionMessage()GetJavaScriptSources()close_older_discussions.cjs via direct importSee these files for a working implementation example.
Conversational skill that interviews users to design new agentic workflows
Route gh-aw workflow design/create/debug/upgrade requests to the right prompts.
Analyze and reduce token consumption in agentic workflows — guardrail-specific entry points, measurement, and optimization techniques.
Implement secret-safe HTTP headers for MCP transport in gh-aw.
Review code that performs git or gh operations against repository checkouts in gh-aw, checking that the right credentials are available at the right time and that sparseness, shallowness and credential-free factors are properly considered.
Teach Copilot how to plan, address, and respond to pull request review feedback.