Guidance for AI agents working in this repository.
Easydict is a macOS dictionary and translation app that supports word lookup, text translation, and OCR screenshot translation.
Note: New development should use modern Swift and SwiftUI APIs available on macOS 13.0+.
Easydict/App/- App entry point, bridging header, assets, localizationEasydict/Swift/- Primary development environment (all new code)Service/- Translation services (Google, Bing, DeepL, OpenAI, etc.)Feature/- Feature modulesModel/- Data modelsUtility/- Extensions and helpersView/- SwiftUI views
Easydict/objc/- Legacy code - Maintenance only, no extensionsService/- Remaining Obj-C services (Baidu, language detection)ViewController/- Window and query view controllersMMKit/- Utility framework
EasydictTests/- Unit tests
Translation services inherit from a base query service. Each service lives in its own directory under Swift/Service/ with:
- Main service class (e.g.,
GoogleService.swift) - Supporting models and extensions as needed
- Swift Package Manager for almost all Swift dependencies (Alamofire, Defaults, etc.)
- CocoaPods for dependency management (Masonry, ReactiveObjC, etc.)
- Bridging header at
Easydict/App/Easydict-Bridging-Header.h - PCH file at
Easydict/App/PrefixHeader.pch - String localization uses Xcode String Catalogs (
Localizable.xcstringsfiles)
Unless the user explicitly says otherwise, when adding or moving files, also update Easydict.xcodeproj/project.pbxproj so the files appear in Xcode's navigator.
- By default, every newly added project file, including developer-facing
Markdown documents such as
README.md, must have a matchingPBXFileReferenceunder the correctPBXGroup. - Do not add documentation files to build phases such as
Resourcesunless the file is intentionally shipped at runtime.
Run xcodebuild only when:
- The substantive code changes exceed 100 lines. Documentation comment-only edits do not count toward this threshold.
- The user explicitly asks for a build or test run.
- The task runs
/code-simplifier.
Do not run multiple xcodebuild commands concurrently against the same workspace and DerivedData location. Concurrent runs can contend for the shared build database, intermediates, and test bundles, which leads to flaky conflicts.
xcodebuild may take several minutes. Wait for it to finish.
If the default Xcode DerivedData location fails because of permission, cache, or runner state, use an external DerivedData directory instead of a repo-local one:
-derivedDataPath ~/Library/Developer/Xcode/DerivedData/Easydict-Codex
After the build or test completes, remove that DerivedData directory before finishing the task.
Common build and test commands:
# Build
xcodebuild build \
-workspace Easydict.xcworkspace \
-scheme Easydict | xcbeautify
# Test (builds and runs a test in one command)
xcodebuild test \
-workspace Easydict.xcworkspace \
-scheme Easydict \
-only-testing:EasydictTests/UtilityFunctionsTests/testAES | xcbeautify
# Build for testing
xcodebuild build-for-testing \
-workspace Easydict.xcworkspace \
-scheme Easydict | xcbeautify
# e.g. run specific test class, -only-testing:<Target>/<TestClass>
xcodebuild test-without-building \
-workspace Easydict.xcworkspace \
-scheme Easydict \
-only-testing:EasydictTests/UtilityFunctionsTests | xcbeautify
# e.g. run specific test method, -only-testing:<Target>/<TestClass>/<testMethod>
xcodebuild test-without-building \
-workspace Easydict.xcworkspace \
-scheme Easydict \
-only-testing:EasydictTests/UtilityFunctionsTests/testAES | xcbeautifyRecommended usage:
build: default validation after code changes.test: simplest one-shot test run; builds and runs tests in one command.build-for-testing+test-without-building: preferred when rerunning the same tests repeatedly.test-without-buildingrequires a compatible priorbuild-for-testingwith the same workspace, scheme, destination, configuration, and DerivedData location.- If code or build settings changed, rerun
build-for-testingbeforetest-without-building. - Prefer
-only-testing:when debugging a specific test class or method.
- Write new code in Swift/SwiftUI only. Legacy Objective-C may receive bug fixes, but no new features.
- Keep source files ideally under 300 lines and never over 500 without strong justification.
- Avoid single-letter variable names except trivial loop indices.
- Avoid
staticfunctions and variables unless type-level semantics clearly require them. Utility types may usestatic. - Do not extract one-off literals into variables or constants unless they are reused or have clear semantic meaning. Name a one-off constant only when a magic number has distinctive visual or domain meaning.
- Prefer
for … whereoverforplus inlineiffiltering. - Prefer async/await over callback-based completion handlers for new async work.
- Add a type-level comment immediately before every class, struct, enum, protocol, and actor. For core types, use 2-4 short sentences and keep the comment around 220-320 English characters. For simple private helper types, use 1-2 short sentences and keep it under 180 characters.
- Keep comment lines within 80 characters, avoid restating obvious type or property names, and update comments whenever responsibilities or behavior change.
- Add English documentation comments for functions when behavior or intent is not obvious. Use inline comments only for non-obvious reasoning or complex logic.
- In Markdown documentation, keep normal prose as natural paragraphs. Hard-wrap only list items, keep them within 90 characters when practical, and preserve continuation indentation.
- When creating or updating source file header comments, use the current Git username in
the
Created by ...line. Do not use agent names such asCodex,Claude, orAI Assistant. - Every directory must include a Chinese
README.md. When creating a new directory, add itsREADME.mdand matching SVG technical diagram in the same change. - Generate each
README.md's SVG technical diagram from the README content with thefireworks-tech-graphskill, choosing the diagram type that best fits the content. - When files in a directory are added, removed, renamed, or their behavior changes, update
that directory's
README.mdand matching SVG technical diagram in the same change. Explain responsibilities, key components, main flows, and debugging entry points instead of writing a method-by-method API index.
.agents/overrides/stores repo-level agent rules that are not bundled into runtime skills. Runtime skill-specific overlays should live inside the target skill directory.- When using
fireworks-tech-graph, read.agents/overrides/fireworks-tech-graph-layout-rules.mdafter the skill and apply the stricter project-level layout, connector, label, export, and rendered-review rules. - If the base skill conflicts with its overlay, keep the stricter project-level overlay rule instead of editing only the upstream skill mirror.
- Use
UpperCamelCasefor directories and files that are compiled by Xcode, including Swift, Objective-C, and test source files. - Use
kebab-casefor directories and files that are not compiled by Xcode, including app-managed runtime paths underApplication Support/<bundle>, scripts, and exported artifacts. - For new or renamed classes, structs, enums, protocols, actors, properties, parameters, and local variables, prefer clear, concise names, remove repeated surrounding context, and usually keep them within 25 characters.
- If a longer name is required by a system API, external protocol, or unavoidable domain term, keep it as short as possible and treat it as an exception.
- Each test source file may declare at most one
@Suitetype. - Do not add tests for UI code or UI-focused changes.
- Add or update tests only for changes with meaningful behavior or correctness risk. Skip trivial pass-through code, simple glue code, obvious accessors, and behavior already covered elsewhere, and run the relevant tests.
- Prefer concrete production code and high-signal behavior assertions. Do not add test-only protocols, mocks, overrides, or invasive production hooks for low-value tests.
- Use SFSafeSymbols type-safe APIs instead of hard-coded SF Symbol strings.
- Prefer
Image(systemSymbol: .chevronRight)overImage(systemName: "chevron.right"). - Prefer
Label("MyText", systemSymbol: .cCircle)overLabel("MyText", systemImage: "c.circle"). - In SwiftUI, use
foregroundStyle<S>(_ style: S)instead of deprecatedforegroundColor(_:). - In SwiftUI, use
background(alignment:content:)or trailing-closurebackground { ... }for background views instead of deprecatedbackground(_:alignment:). KeepColorand materialShapeStylebackgrounds on their dedicated overloads. - Use
Alamofireasync/await APIs for network requests. - Use
Defaultsfor user preferences and settings; avoid introducing new directUserDefaultsusage.
- All user-facing UI text must be localized. Do not hard-code visible strings in SwiftUI or AppKit.
- Use static String Catalog keys directly in UI and string APIs, for example
Text("setting.general.appearance.light_dark_appearance"). - Do not build localization keys dynamically or concatenate localized fragments. For text with runtime values, localize the full sentence with a dedicated entry and pass the values as arguments.
- Use lowercase, dot-separated keys with snake_case segments where needed, and do not
rename keys casually. Follow
<scope>.<category>.<subcategory>.<element>, for examplecommon.doneorsetting.general.appearance.light_dark_appearance. Localizable.xcstringsmanages app string localization. Whenever localized strings are added or changed, update the corresponding entries in this file and keep every supported language in sync.
Always use the OpenAI developer documentation MCP server if you need to work with the OpenAI API, ChatGPT Apps SDK, Codex,… without me having to explicitly ask.