OpenClaw: Unify AI agent configs with shared persona symlinks (#4653)

Replace vendor-specific config (.augment-guidelines, .augmentignore) with
a unified approach: .claude/, .codex/, and .kiro/ directories all symlink
to the canonical persona files in openclaw/ (SOUL.md, USER.md, MEMORY.md,
IDENTITY.md, TOOLS.md, AGENTS.md).

All artificial intelligence programming entities, including Claude Code, Codex, 
and Kiro, possess commonality. the same identity, memory, and conventions 
without file duplication.

- Remove .augment-guidelines and .augmentignore (Augment AI)
- Add .claude/ with settings.local.json hook to auto-load persona files
- Add .codex/ with config.toml and CODEX.md instruction entrypoint
- Rename .agents/skills to .codex/skills
- Add .kiro/steering/ with persona symlinks
- Document ACP working directory convention in TOOLS.md
- Update openclaw/.gitignore for .pi and extensions directories

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Winlin 2026-03-22 10:37:09 -04:00 committed by GitHub
parent ebf8b712c9
commit f48b2b31d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 64 additions and 403 deletions

View File

@ -1,357 +0,0 @@
# SRS Repository Guidelines
project:
name: "SRS (Simple Realtime Server)"
type: "C++ streaming media server (RTMP/WebRTC/WHIP/WHEP/SRT/HLS/HTTP-FLV)"
architecture:
overview: "C++ streaming server using State Threads (ST) for coroutine-based networking"
threading: "Single-threaded coroutine architecture - no multi-threading, context switches on async I/O"
key_classes: "SrsServer (main), SrsLiveSource (source management)"
webrtc: "SFU (Selective Forwarding Unit) - media relay without transcoding. Supports WHIP/WHEP. NO external TURN needed (SRS provides ICE/relay)"
origin_cluster:
v6_mesh: "DEPRECATED - C++ MESH mode, RTMP only"
v7_proxy: "RECOMMENDED - Go-based [proxy](./proxy/cmd/proxy-go), all protocols, better scaling"
codebase_structure:
dirs: "trunk/src/{main,core,kernel,protocol,app}"
key_files: "srs_main_server.cpp, srs_app_server.hpp, srs_core.hpp, srs_core_autofree.hpp"
code_patterns:
dependency_inversion:
principle: "MANDATORY - Depend on interfaces (ISrs*), not concrete classes (Srs*)"
rules:
- "Member variables use ISrs* types (e.g., ISrsMessageQueue *queue_)"
- "Concrete types only for instantiation"
- "Enables mocking for unit tests"
avoid_global_variables:
principle: "MANDATORY - Store globals (_srs_*) as member fields for mockability"
pattern: |
Constructor: config_ = _srs_config; // Store reference
Destructor: config_ = NULL; // Set NULL, don't free
Methods: Use config_->method() instead of _srs_config->method()
common_globals: "_srs_config, _srs_sources, _srs_stat, _srs_hooks, _srs_context, _srs_log, _srs_server"
cpp_compatibility:
standard: "C++98 only - NO C++11+ features"
forbidden: "auto, nullptr, range-for, lambda, std::unique_ptr, enum class, override, constexpr"
use: "NULL, traditional for-loops, typedef, SrsUniquePtr/SrsSharedPtr"
memory_management:
smart_pointers: "SrsUniquePtr<T> (unique ownership), SrsSharedPtr<T> (shared ownership)"
macros: "srs_freep (pointers), srs_freepa (arrays) - use only when smart pointers unsuitable"
naming_conventions:
- pattern: "field_naming"
description: "MANDATORY - All class and struct fields (member variables) must end with underscore (_), but NOT functions/methods"
usage: |
WRONG: Fields without underscore
class SrsBuffer {
private:
char *p;
int size;
public:
bool enabled;
};
CORRECT: Fields with underscore, functions without underscore
class SrsBuffer {
private:
char *p_;
int size_;
public:
bool enabled_;
public:
srs_error_t initialize();
};
scope: "Applies ONLY to fields (member variables) in classes and structs - NOT to functions, methods, comments, error messages, or parameters"
exceptions: "Only applies to SRS-defined classes/structs - do NOT change 3rd party code like llhttp"
rationale: "Consistent naming convention across SRS codebase for better code readability and maintenance - underscore distinguishes member variables from local variables and parameters"
access_specifiers_for_testing:
- pattern: "SRS_DECLARE_PRIVATE and SRS_DECLARE_PROTECTED macros"
description: "MANDATORY - Always use SRS_DECLARE_PRIVATE instead of 'private' and SRS_DECLARE_PROTECTED instead of 'protected' in class definitions"
purpose: "Enables unit tests to access private and protected members for dependency injection and mocking"
usage: |
CORRECT: Using SRS access specifier macros
class SrsBufferCache {
SRS_DECLARE_PRIVATE:
ISrsAppConfig *config_;
ISrsRequest *req_;
SRS_DECLARE_PROTECTED:
virtual srs_error_t do_start();
public:
srs_error_t start();
};
rules:
- "ALWAYS use SRS_DECLARE_PRIVATE instead of 'private' keyword"
- "ALWAYS use SRS_DECLARE_PROTECTED instead of 'protected' keyword"
- "Use standard 'public' keyword for public members (no macro needed)"
- "This applies to ALL production code classes in trunk/src/"
- "When SRS_FORCE_PUBLIC4UTEST is defined, all private/protected members become public for testing"
commenting_style:
- pattern: "C++ style comments"
description: "MANDATORY - Use C++ style comments (//) instead of C style comments (/* */)"
usage: |
WRONG: C style comments
/* This is a comment */
/**
* Multi-line comment
* with multiple lines
*/
CORRECT: C++ style comments
// This is a comment
// Multi-line comment
// with multiple lines
rationale: "Consistent with SRS codebase style and better for single-line documentation"
- pattern: "No thread-safety comments"
description: "Do NOT describe thread-safety in comments since SRS is a single-threaded application"
usage: |
WRONG: Mentioning thread-safety
// This implementation is thread-safe for single-threaded usage but may
// require external synchronization in multi-threaded environments.
CORRECT: Focus on functionality without thread-safety mentions
// This implementation maintains state between calls for consistent
// round-robin behavior across multiple selections.
rationale: "SRS uses single-threaded coroutine-based architecture, so thread-safety discussions are irrelevant and confusing"
error_handling:
- pattern: "srs_error_t"
description: "Custom error handling system - MANDATORY for all functions that return srs_error_t"
- pattern: "error_checking_and_wrapping"
description: "MANDATORY pattern for calling functions that return srs_error_t - ALWAYS check and wrap errors"
usage: |
WRONG: Not checking error return value (causes error object leak)
muxer_->write_audio(shared_audio, format);
reader.read(start, filesize, &nread);
CORRECT: Always check error and wrap with context
if ((err = muxer_->write_audio(shared_audio, format)) != srs_success) {
return srs_error_wrap(err, "write audio");
}
ssize_t nread = 0;
if ((err = reader.read(start, filesize, &nread)) != srs_success) {
return srs_error_wrap(err, "read %d only %d bytes", filesize, (int)nread);
}
rationale: |
- Prevents error object memory leaks
- Provides proper error context propagation
- Includes relevant local variables in error messages for debugging
- Maintains error chain for better troubleshooting
- pattern: "error_wrapping_with_context"
description: "When wrapping errors, include relevant local variables and context information"
rules:
- "Always include newly created local variables in error messages"
- "Include function parameters that provide context"
- "Use descriptive error messages that explain what operation failed"
- "Format numeric values appropriately (cast to int for display if needed)"
examples:
- "return srs_error_wrap(err, \"read %d only %d bytes\", filesize, (int)nread);"
- "return srs_error_wrap(err, \"write audio format=%d\", format->codec);"
- "return srs_error_wrap(err, \"connect to %s:%d\", host.c_str(), port);"
binary_data_handling:
- pattern: "SrsBuffer"
description: "MANDATORY utility for marshaling and unmarshaling structs with bytes - ALWAYS use this instead of manual byte manipulation"
usage: |
WRONG: Manual byte manipulation
char* buf = new char[4];
buf[0] = 0xff;
buf[1] = (value >> 8) & 0xFF;
buf[2] = value & 0xFF;
CORRECT: Use SrsBuffer
char* buf = new char[4];
SrsBuffer buffer(buf, 4);
buffer.write_1bytes(0xff);
buffer.write_2bytes(value);
key_methods:
read: "read_1bytes(), read_2bytes(), read_4bytes(), read_8bytes(), read_string(len), read_bytes(data, size)"
write: "write_1bytes(), write_2bytes(), write_4bytes(), write_8bytes(), write_string(), write_bytes()"
utility: "pos(), left(), empty(), require(size), skip(size)"
rationale: "Provides consistent byte-order handling, bounds checking, and position tracking for binary data operations"
time_handling:
- pattern: "srs_utime_t"
description: "MANDATORY type for all time variables - ALWAYS use srs_utime_t instead of int64_t for time values"
usage: |
WRONG: Using int64_t for time
int64_t now = srs_get_system_time();
int64_t duration = end_time - start_time;
int64_t timeout_ms = timeout / 1000;
CORRECT: Use srs_utime_t for time
srs_utime_t now = srs_get_system_time();
srs_utime_t duration = now - start_time;
int timeout_ms = srsu2msi(timeout);
rationale: "srs_utime_t provides consistent time handling across platforms and ensures proper microsecond precision"
- pattern: "srs_get_system_time()"
description: "Standard function to get current system time in microseconds"
usage: "srs_utime_t now = srs_get_system_time();"
- pattern: "duration calculation"
description: "Calculate time duration using simple subtraction"
usage: |
srs_utime_t starttime = srs_get_system_time();
// ... some operations ...
srs_utime_t duration = srs_get_system_time() - starttime;
int duration_ms = srsu2ms(duration);
note: "For simple cases, use direct subtraction. srs_duration() function is available for special cases with zero checks."
- pattern: "srsu2ms(us)"
description: "MANDATORY macro to convert microseconds to milliseconds - ALWAYS use instead of division by 1000"
usage: |
WRONG: Manual division
int ms = now / 1000;
int timeout_ms = timeout / 1000;
CORRECT: Use srsu2ms macro
int ms = srsu2ms(now);
int timeout_ms = srsu2ms(timeout);
rationale: "Provides consistent conversion and avoids magic numbers"
- pattern: "srsu2msi(us)"
description: "Convert microseconds to milliseconds as integer"
usage: "int ms = srsu2msi(timeout);"
- pattern: "srsu2s(us) / srsu2si(us)"
description: "Convert microseconds to seconds"
usage: "int seconds = srsu2si(duration);"
- pattern: "time_constants"
description: "Standard time constants for SRS"
constants:
- "SRS_UTIME_MILLISECONDS (1000) - microseconds in one millisecond"
- "SRS_UTIME_SECONDS (1000000LL) - microseconds in one second"
- "SRS_UTIME_MINUTES (60000000LL) - microseconds in one minute"
- "SRS_UTIME_HOURS (3600000000LL) - microseconds in one hour"
- "SRS_UTIME_NO_TIMEOUT - special value for no timeout"
- pattern: "best_practices"
description: "Time handling best practices"
practices:
- "Always declare time variables as srs_utime_t, never int64_t"
- "Use srs_get_system_time() to get current time"
- "Use simple subtraction (end - start) for calculating time differences"
- "Use srsu2ms() family macros for time unit conversions"
- "Use time constants (SRS_UTIME_SECONDS, etc.) for time arithmetic"
- "Check for SRS_UTIME_NO_TIMEOUT when handling timeout values"
conditional_compilation:
- pattern: "#ifdef SRS_VALGRIND"
description: "Valgrind support"
codec_handling:
enhanced_rtmp:
description: |
For HEVC and other new codecs in RTMP/FLV protocols, always use enhanced-RTMP codec fourcc instead of legacy RTMP codec IDs.
Enhanced-RTMP provides better support for modern codecs and is the preferred approach.
NOTE: This guidance applies ONLY to RTMP/FLV protocols, not to other protocols like SRT/WebRTC/WHIP/WHEP/HLS/DASH/GB28181.
hevc_codec:
- pattern: "fourcc: hvc1"
description: "Use enhanced-RTMP fourcc 'hvc1' for HEVC codec identification in RTMP/FLV"
usage: "Always use fourcc 'hvc1' for HEVC instead of legacy RTMP codecid(12)"
rationale: "Enhanced-RTMP fourcc provides better codec identification and compatibility"
general_rule:
- "Do NOT use legacy RTMP codecid(12) for HEVC"
- "Always prefer enhanced-RTMP codec fourcc for new codecs"
- "Use fourcc format for codec identification in enhanced-RTMP contexts"
- "This applies ONLY to RTMP/FLV protocols - other protocols use their own codec identification methods"
build_and_development:
build:
command: "make -j"
description: "Build the SRS server using parallel make in the trunk directory"
working_directory: "trunk"
run_utests:
command: "make utest -j && ./objs/srs_utest"
description: "Run the unit tests for SRS"
working_directory: "trunk"
run_blackbox_tests:
description: "Blackbox tests are integration tests that test SRS as a complete system using FFmpeg as client"
location: "trunk/3rdparty/srs-bench/blackbox/"
prerequisites:
- "SRS server binary must be built first (make -j in trunk/)"
- "FFmpeg and FFprobe must be available in PATH"
- "Test media files (avatar.flv, etc.) must be present in srs-bench directory"
build_blackbox_tests:
command: "cd trunk/3rdparty/srs-bench && make"
description: "Build the blackbox test binary"
output: "./objs/srs_blackbox_test"
run_all_tests:
command: "./objs/srs_blackbox_test -test.v -srs-log -srs-stdout"
description: "Run all blackbox tests with verbose output and detailed SRS logs"
working_directory: "trunk/3rdparty/srs-bench"
testing:
utest_file_naming:
description: "Unit test file naming indicates ownership and maintenance responsibility"
patterns:
- "srs_utest_ai*.cpp - AI-managed, AI has full autonomy"
- "srs_utest_workflow_*.cpp - Human-dominated with AI help, human maintains"
- "srs_utest_manual_*.cpp - Human-written, AI should NOT modify without permission"
error_handling_macros:
- Use HELPER_EXPECT_SUCCESS(x) when expecting a function to succeed (returns srs_success)
- Use HELPER_EXPECT_FAILED(x) when expecting a function to fail (returns non-srs_success error)
- These macros automatically handle error cleanup and provide better error messages
- Always declare "srs_error_t err;" at the beginning of test functions that use these macros
- |
Example:
VOID TEST(MyTest, TestFunction) {
srs_error_t err;
HELPER_EXPECT_SUCCESS(some_function_that_should_succeed());
HELPER_EXPECT_FAILED(some_function_that_should_fail());
}
debugging:
memory_and_pointer_issues:
description: "For memory corruption, crashes, pointer issues, or undefined behavior, proper debugging information is MANDATORY"
required_information: "User MUST provide either coredump stack trace OR sanitizer output - without it, memory issues cannot be diagnosed"
sanitizer:
description: "AddressSanitizer (ASAN) - Google's memory error detection tool for catching buffer overflows, use-after-free, memory leaks, etc."
when_enabled: "Automatically enabled for unit tests (--utest=on), manually enabled with ./configure --sanitizer=on, disabled by default for production builds (causes memory leak and increasing forever)"
how_to_enable: "./configure --sanitizer=on && make"
coredump:
description: "When sanitizer cannot be used, coredump with stack trace is required"
how_to_get: "ulimit -c unlimited, run SRS until crash, gdb ./objs/srs core.xxx -ex 'bt' -ex 'quit'"
code_review:
github_pull_requests:
- When reviewing or understanding GitHub pull requests, use the diff URL to get the code changes
- Format: https://patch-diff.githubusercontent.com/raw/ossrs/srs/pull/{PR_NUMBER}.diff
- Example: For PR #4289, access https://patch-diff.githubusercontent.com/raw/ossrs/srs/pull/4289.diff
- This provides the raw diff showing all changes made in the pull request
- Use web-fetch tool to retrieve and analyze the diff content
documentation:
location: "3rdparty/srs-docs"
description: |
SRS documentation source files are located in the 3rdparty/srs-docs directory
usage: |
When looking for documentation or need to update docs, check this directory for markdown
files and documentation structure. Do not search ossrs.io or ossrs.net for documentation,
use the local files instead.

View File

@ -1,44 +0,0 @@
# Build artifacts
**/objs/**
**/build/**
**/*.o
**/*.a
**/*.so
**/*.dylib
# IDE files
**/.idea/**
**/.vscode/**
**/.run/**
# Generated files
**/*.exe
**/*.flv
**/*.mp4
**/*.ts
# 3rd party libraries
**/3rdparty/ffmpeg-4-fit/**
**/3rdparty/gperftools-2-fit/**
**/3rdparty/gprof/**
**/3rdparty/gtest-fit/**
**/3rdparty/httpx-static/**
**/3rdparty/libsrtp-2-fit/**
**/3rdparty/openssl-1.1-fit/**
**/3rdparty/patches/**
**/3rdparty/signaling/**
**/3rdparty/srt-1-fit/**
**/3rdparty/srs-bench/vendor/**
# Research files.
**/tools/**
**/research/**
# Other files.
**/packaging/**
**/scripts/**
**/usr/**
**/.github/**
**/gdb/**
**/cmake/**

1
.claude/CLAUDE.md Symbolic link
View File

@ -0,0 +1 @@
../openclaw/AGENTS.md

1
.claude/IDENTITY.md Symbolic link
View File

@ -0,0 +1 @@
../openclaw/IDENTITY.md

1
.claude/MEMORY.md Symbolic link
View File

@ -0,0 +1 @@
../openclaw/MEMORY.md

1
.claude/SOUL.md Symbolic link
View File

@ -0,0 +1 @@
../openclaw/SOUL.md

1
.claude/TOOLS.md Symbolic link
View File

@ -0,0 +1 @@
../openclaw/TOOLS.md

1
.claude/USER.md Symbolic link
View File

@ -0,0 +1 @@
../openclaw/USER.md

View File

@ -0,0 +1,16 @@
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "content=\"\"; for f in .claude/SOUL.md .claude/USER.md .claude/MEMORY.md .claude/IDENTITY.md .claude/TOOLS.md; do if [ -f \"$f\" ]; then content=\"$content\\n--- $f ---\\n$(cat \"$f\")\"; fi; done; jq -n --arg ctx \"$content\" '{hookSpecificOutput: {hookEventName: \"SessionStart\", additionalContext: $ctx}}'",
"timeout": 10,
"statusMessage": "Loading SOUL.md, USER.md, MEMORY.md, IDENTITY.md, TOOLS.md..."
}
]
}
]
}
}

1
.codex/AGENTS.md Symbolic link
View File

@ -0,0 +1 @@
../openclaw/AGENTS.md

8
.codex/CODEX.md Normal file
View File

@ -0,0 +1,8 @@
Load this files automatically when startup:
- AGENTS.md
- CODEX.md
- IDENTITY.md
- MEMORY.md
- SOUL.md
- TOOLS.md
- USER.md

1
.codex/IDENTITY.md Symbolic link
View File

@ -0,0 +1 @@
../openclaw/IDENTITY.md

1
.codex/MEMORY.md Symbolic link
View File

@ -0,0 +1 @@
../openclaw/MEMORY.md

1
.codex/SOUL.md Symbolic link
View File

@ -0,0 +1 @@
../openclaw/SOUL.md

1
.codex/TOOLS.md Symbolic link
View File

@ -0,0 +1 @@
../openclaw/TOOLS.md

1
.codex/USER.md Symbolic link
View File

@ -0,0 +1 @@
../openclaw/USER.md

7
.codex/config.toml Normal file
View File

@ -0,0 +1,7 @@
#:schema https://developers.openai.com/codex/config-schema.json
# Codex currently supports one explicit instruction entrypoint file.
# That file can then instruct Codex to read additional local files at session start.
model_instructions_file = "CODEX.md"
project_doc_fallback_filenames = ["AGENTS.md", "IDENTITY.md", "MEMORY.md", "SOUL.md", "TOOLS.md", "USER.md"]
project_doc_max_bytes = 131072

1
.kiro/steering/AGENTS.md Symbolic link
View File

@ -0,0 +1 @@
../../openclaw/AGENTS.md

1
.kiro/steering/IDENTITY.md Symbolic link
View File

@ -0,0 +1 @@
../../openclaw/IDENTITY.md

1
.kiro/steering/MEMORY.md Symbolic link
View File

@ -0,0 +1 @@
../../openclaw/MEMORY.md

1
.kiro/steering/SOUL.md Symbolic link
View File

@ -0,0 +1 @@
../../openclaw/SOUL.md

1
.kiro/steering/TOOLS.md Symbolic link
View File

@ -0,0 +1 @@
../../openclaw/TOOLS.md

1
.kiro/steering/USER.md Symbolic link
View File

@ -0,0 +1 @@
../../openclaw/USER.md

4
openclaw/.gitignore vendored
View File

@ -1,4 +1,6 @@
/.openclaw/workspace-state.json /.openclaw/workspace-state.json
/.clawhub /.clawhub
/.pi
/extensions
/skills/llm-switcher /skills/llm-switcher
/personal /personal

View File

@ -40,6 +40,16 @@ Skills are shared. Your setup is yours. Keeping them apart means you can update
- Channel: `telegram`, accountId: `srs` (SRS bot) - Channel: `telegram`, accountId: `srs` (SRS bot)
- When sending to William's Telegram: `channel: "telegram"`, `accountId: "srs"` - When sending to William's Telegram: `channel: "telegram"`, `accountId: "srs"`
### ACP Working Directory
- My OpenClaw workspace may be a subdirectory like `~/git/srs/openclaw`. That is **my assistant workspace**, not necessarily the real project directory for ACP coding work.
- When delegating project work to ACP agents (Claude/Codex/Gemini/Kiro/etc), do **not** assume the OpenClaw workspace is the project root.
- First ask: **Is the real project directory the parent of the current OpenClaw workspace?** In this setup, yes: workspace is `~/git/srs/openclaw`, while the SRS project directory is the **parent directory** `~/git/srs`.
- Treat this as the default pattern unless the task clearly targets OpenClaw itself: **workspace = assistant home, parent directory = actual project root**.
- For ACP project tasks, prefer the **parent directory of the current workspace** as cwd when that parent is the real repo/project root.
- Use the OpenClaw workspace itself only for OpenClaw-specific/meta tasks.
- The key idea: ACP should see the **project first**, not the assistant's memory/persona files.
### Git Commit Workflow ### Git Commit Workflow
- **Never `git add`** — William stages files himself - **Never `git add`** — William stages files himself

View File

@ -7,6 +7,7 @@ The changelog for SRS.
<a name="v7-changes"></a> <a name="v7-changes"></a>
## SRS 7.0 Changelog ## SRS 7.0 Changelog
* v7.0, 2026-03-22, Merge [#4653](https://github.com/ossrs/srs/pull/4653): OpenClaw: unify AI agent configs with shared persona symlinks. v7.0.140 (#4653)
* v7.0, 2026-03-22, Merge [#4652](https://github.com/ossrs/srs/pull/4652): Proxy: restructure repo as Go project with proxy as first module. v7.0.139 (#4652) * v7.0, 2026-03-22, Merge [#4652](https://github.com/ossrs/srs/pull/4652): Proxy: restructure repo as Go project with proxy as first module. v7.0.139 (#4652)
* v7.0, 2026-03-05, Merge [#4643](https://github.com/ossrs/srs/pull/4643): OpenClaw: add and refine ST knowledge-base and learning/review skills. v7.0.138 (#4643) * v7.0, 2026-03-05, Merge [#4643](https://github.com/ossrs/srs/pull/4643): OpenClaw: add and refine ST knowledge-base and learning/review skills. v7.0.138 (#4643)
* v7.0, 2025-12-31, Merge [#4618](https://github.com/ossrs/srs/pull/4618): HLS/DASH: Fix dispose() to cleanup files even after on_unpublish() sets enabled_ to false. v7.0.137 (#4618) * v7.0, 2025-12-31, Merge [#4618](https://github.com/ossrs/srs/pull/4618): HLS/DASH: Fix dispose() to cleanup files even after on_unpublish() sets enabled_ to false. v7.0.137 (#4618)

View File

@ -9,6 +9,6 @@
#define VERSION_MAJOR 7 #define VERSION_MAJOR 7
#define VERSION_MINOR 0 #define VERSION_MINOR 0
#define VERSION_REVISION 139 #define VERSION_REVISION 140
#endif #endif