diff --git a/text/0626-invoke-helper.md b/text/0626-invoke-helper.md
new file mode 100644
index 0000000000..f154557b8b
--- /dev/null
+++ b/text/0626-invoke-helper.md
@@ -0,0 +1,562 @@
+- Start Date: 2020-04-30
+- Relevant Team(s): Ember.js
+- RFC PR: https://github.com/emberjs/rfcs/pull/626
+- Tracking: (leave this empty)
+
+# JavaScript Helper Invocation API
+
+## Summary
+
+This RFC proposes a new API, `invokeHelper`, which can be used to invoke a
+helper definition, creating an instance of the helper in JavaScript.
+
+```js
+// app/components/data-loader.js
+import Component from '@glimmer/component';
+import Helper from '@ember/component/helper';
+import { invokeHelper } from '@ember/helper';
+
+class PlusOneHelper extends Helper {
+ compute([num]) {
+ return number + 1;
+ }
+}
+
+export default class PlusOne extends Component {
+ plusOne = invokeHelper(this, PlusOneHelper, () => {
+ return {
+ positional: [this.args.number],
+ };
+ });
+}
+```
+```hbs
+{{this.plusOne.value}}
+```
+
+## Motivation
+
+As Ember has evolved, the framework has been developing a model of reactive,
+incremental computation. This model is oriented around _templates_, which map
+data and JavaScript business logic into HTML that is displayed to the user.
+
+On the first render, this mapping is fairly similar to standard programming
+languages. You can imagine that every component is like a _function call_,
+receiving arguments and data, processing it, and placing it within its own
+template, ultimately producing HTML as the "return value" of the component.
+Components can use other components, much like functions can call other
+functions, resulting in a tree structure of nested components, which is
+the application. At the root of our application is a single "main" component
+(similar to the main function in many programming languages) which takes
+arguments and returns the full HTML of the initial render.
+
+Where Ember's programming model really begins to differ is in _subsequent_
+renders. Rather than re-running the entire program whenever something changes,
+producing new HTML as a result, Ember incrementally re-runs the portions of the
+program which have changed. It knows about these portions via its change
+tracking mechanism, _autotracking_.
+
+This means fundamentally that the tree of components differs from a tree of
+functions because components can _live longer_. They exist until the portion of
+the program that they belong to has been removed by an incremental update, and
+as such, they have a _lifecycle_. Unlike a function, a component can _update_
+over time, and will be _destroyed_ at some unknown point in the future.
+
+Components previously exposed this lifecycle directly via a number of
+lifeycle hooks, making components the smallest _atom_ for reactive composition.
+This presented an issue for composability in general. In the world of functions,
+a piece of code can always be broken out into a new function, giving the user
+the ability to extract repeated functionality, abstracting common patterns and
+concepts and reducing brittleness. For instance, in the following example we
+extract several portions of the `myProgram` function to make it clearer what
+each section is doing, and isolate its behavior.
+
+```js
+// before
+function myProgram(data = []) {
+ for (let item of data) {
+ // ...
+ }
+
+ let values = data.map(() => {
+ // ...
+ });
+
+ while (values.length) {
+ let value = values.pop();
+ // ...
+ }
+}
+```
+```js
+// after
+function initialProcessing(data) {
+ for (let item of data) {
+ // ...
+ }
+}
+
+function extractValues(data) {
+ return data.map(() => {
+ // ...
+ });
+}
+
+function processValues(values) {
+ while (values.length) {
+ let value = values.pop();
+ // ...
+ }
+}
+
+function myProgram(data = []) {
+ initialProcessing(data);
+
+ let values = extractValues(data);
+
+ processValues(values);
+}
+```
+
+Since components are the smallest reactive atom, there often is not a way to do this
+transparently, since the only portions of the code that are reactive are the
+component hooks themselves. This results in related code being spread across
+multiple locations, with the user being forced to keep the relationships between
+these bits of code in their head at all times, and understand the interactions
+between them.
+
+Consider this search component, which updates performs a cancellable fetch
+request and updates the document title whenever the search query is updated:
+
+```js
+import Component from '@ember/component';
+import { fetch, cancelFetch } from 'fetch-with-cancel';
+
+export default class Search extends Component {
+ // Args
+ query = '';
+
+ @tracked data;
+
+ didReceiveAttrs() {
+ // Update the document title
+ document.title = `Search Result for "${this.query}"`;
+
+ // Cancel the previous fetch if it's still running
+ cancelFetch(this.promise);
+
+ // create a new fetch request, and set the data property to the response
+ this.promise = fetch(`www.example.com/search?query=${this.query}`)
+ .then((response) => response.json());
+ .then((data) => this.data = data);
+ }
+
+ willDestroy() {
+ cancelFetch(this.promise);
+ }
+}
+```
+
+This component mixes two separate concerns in its lifecycle hooks - fetching the
+data, and updating the document title. We can extract these into utility
+functions in some isolated cases, but it becomes difficult when functionality
+covers multiple parts of the lifecycle, like with the fetch logic here:
+
+```js
+import Component from '@ember/component';
+import { fetch, cancelFetch } from 'fetch-with-cancel';
+
+function updateDocumentTitle(title) {
+ document.title = title;
+}
+
+function updateFetch(url, callback, previousPromise) {
+ // Cancel the previous fetch if it's still running
+ cancelFetch(previousPromise);
+
+ // create a new fetch request, and set the data property to the response
+ return fetch(url)
+ .then((response) => response.json());
+ .then((data) => callback(data));
+}
+
+function teardownFetch(promise) {
+ cancelFetch(promise);
+}
+
+export default class Search extends Component {
+ // Args
+ query = '';
+
+ @tracked data;
+
+ didReceiveAttrs() {
+ updateDocumentTitle(`Search Result for "${this.query}"`)
+
+ this.promise = updateFetch(
+ `www.example.com/search?query=${this.query}`,
+ (data) => this.data = data,
+ this.promise
+ );
+ }
+
+ willDestroy() {
+ teardownFetch(this.promise);
+ }
+}
+```
+
+We can see here that we needed to add two separate helper functions to extract
+the data fetching functionality, one to handle updating the fetch, and one to
+handle tearing it down, because those different pieces of code need to run at
+different portions of the component lifecycle. If we want to reuse these
+functions elsewhere, this adds a lot of boilerplate to integrate the functions
+in each lifecycle hook.
+
+There are a few alternatives that would allow us to extract this functionality
+together.
+
+1. We could use mixins, since they allow us to specify multiple functions and
+ mix them into a class. Mixins however introduce a lot of complexity in the
+ inheritance hierarchy and are considered an antipattern, so this is not a
+ good choice overall.
+
+2. We could extract the functionality out to separate components. Components
+ have a contained lifecycle, so they can manage any piece of functionality
+ completely in isolation. This works nicely for the document title, but adds
+ a lot of complexity for the data fetching, since we need to yield the data
+ back out via the template:
+
+ ```js
+ // app/components/doc-title.js
+ import Component from '@ember/component';
+
+ export default class DocTitle extends Component {
+ didReceiveAttrs() {
+ document.title = this.title;
+ }
+ }
+ ```
+ ```js
+ // app/components/fetch-data.js
+ import Component from '@ember/component';
+ import { fetch, cancelFetch } from 'fetch-with-cancel';
+
+ export default class FetchData extends Component {
+ @tracked data;
+
+ didReceiveAttrs() {
+ // Cancel the previous fetch if it's still running
+ cancelFetch(this.promise);
+
+ // create a new fetch request, and set the data property to the response
+ this.promise = fetch(this.url)
+ .then((response) => response.json());
+ .then((data) => this.data = data);
+ }
+
+ willDestroy() {
+ cancelFetch(this.promise);
+ }
+ }
+ ```
+ ```hbs
+
+ {{yield this.data}}
+ ```
+ ```hbs
+
+
+
+
+ ...
+
+ ```
+
+ This structure is also not ideal because the components aren't being used for
+ templating, they're just being used for logic effectively.
+
+3. We could use other template constructs, such as helpers or modifiers. Both
+ helpers and modifiers have lifecycles, like components, and can be used to
+ contain functionality. Modifiers aren't really a good choice here though,
+ because it would require us to add an element that we don't need. So, helpers
+ are the better option.
+
+ Helpers work, but like components they require us to move some of our logic
+ into the template, even if that isn't really necessary:
+
+ ```js
+ // app/helpers/doc-title.js
+ import { helper } from '@ember/component/helper';
+
+ export default helper(([title]) => {
+ document.title = title;
+ });
+ ```
+ ```js
+ // app/helpers/fetch-data.js
+ import Helper from '@ember/component/helper';
+ import { fetch, cancelFetch } from 'fetch-with-cancel';
+
+ export default class FetchData extends Helper {
+ @tracked data;
+
+ compute([url]) {
+ if (this._url !== url) {
+ this.url = url;
+
+ // Cancel the previous fetch if it's still running
+ cancelFetch(this.promise);
+
+ // create a new fetch request, and set the data property to the response
+ this.promise = fetch(url)
+ .then((response) => response.json());
+ .then((data) => this.data = data);
+ }
+
+ return this.data;
+ }
+
+ willDestroy() {
+ cancelFetch(this.promise);
+ }
+ }
+ ```
+ ```hbs
+
+ {{doc-title 'Search Result for "{{@query}}"'}}
+
+ {{#let (fetch-data "www.example.com/search?query={{@query}}") as |data|}}
+ ...
+ {{/let}}
+ ```
+
+Out of these options, helpers are the closest to what we want - they produce
+computed values directly without a template, and with the recent addition of
+effect helpers they can be used side-effect to accomplish tasks like setting the
+document title. The only downside is that they can only be invoked in templates,
+so they require you to design your components around using them in templates
+only. This can be difficult to do in many cases, where the data wants to be
+accessed to create derived state for instance.
+
+This RFC proposes adding a way to create helpers within JavaScript directly,
+extending the reactive model in a way that allows users to extract common
+reactive code and patterns, and reuse them transparently. This will make helpers
+the new reactive atom of the system - the reactive equivalent of a "function" in
+our incremental model. Like components, they have a lifecycle, and can update
+over time. Unlike components, they can exist nested in JavaScript classes _and_
+in templates, and they can produce any type of value, making them much more
+flexible.
+
+```js
+// app/components/search.js
+import Component from '@ember/component';
+
+export default class Search extends Component {
+ data = invokeHelper(this, FetchData, () => {
+ return {
+ positional: [`www.example.com/search?query=${this.query}`],
+ };
+ });
+
+ constructor() {
+ super(...arguments);
+
+ invokeHelper(this, DocTitle, () => {
+ return {
+ positional: [`Search Result for "${this.query}"`],
+ };
+ });
+ }
+}
+```
+
+Note how the concerns are completely separated in this version of the component.
+The polling logic is self contained, and separated from the data fetching logic.
+Both sets of logic are able to contain their lifecycles, updating based on
+changes to tracked state, and tearing down when the program destroys them. In
+the future, convenience APIs can be added to make invoking them easier to read:
+
+```js
+export default class Search extends Component {
+ @use data = fetchData(() => `www.example.com/search?query=${this.query}`);
+
+ constructor() {
+ super(...arguments);
+
+ use(this, docTitle(() => `Search Result for "${this.query}"`));
+ }
+}
+```
+
+## Detailed design
+
+This RFC proposes adding the `invokeHelper` function, imported from
+`@ember/helper`. The function will have the following interface (using
+TypeScript types for brevity and clarity):
+
+```ts
+interface TemplateArgs {
+ positional?: unknown[],
+ named?: Record
+}
+
+type HelperDefinition = object;
+
+function invokeHelper(
+ parentDestroyable: object,
+ definition: HelperDefinition,
+ computeArgs?: (context: object) => TemplateArgs
+): Cache;
+```
+
+Let's step through the arguments to the function one by one:
+
+#### `parentDestroyable`
+
+This is the parent for the helper definition. The helper will be associated as a
+destroyable to this parent context, using the [destroyables API](https://github.com/emberjs/rfcs/blob/master/text/0580-destroyables.md),
+so that its lifecycle is tied to the parent. The only requirement of the parent
+is that it is an object of some kind that can be destroyed. If the parent has an
+owner, this owner will also be passed to the helper manager that it is invoked on.
+
+This allows helper's lifecycles to be entangled correctly with the parent, and
+encourages users to ensure they've properly handled the lifecycle of their
+helper.
+
+#### `definition`
+
+This is the helper definition. It can be any object, with the only requirement
+being that a helper manager has been associated with it via the
+[`setHelperManager` API](https://github.com/emberjs/rfcs/blob/master/text/0625-helper-managers.md#detailed-design).
+
+#### `computeArgs`
+
+This is an optional function that produces the arguments to the helper. The
+function receives the parent context as an argument, and must return an object
+with a `positional` property that is an array and/or a `named` property that is
+an object.
+
+This getter function will be _autotracked_ when it is run, so the process of
+retrieving the arguments is autotracked. If any of the values used to create the
+arguments object change, the helper will be updated, just like in templates.
+
+### Return Value
+
+The function returns a Cache instance, as defined in the [Autotracking Memoization RFC](https://github.com/emberjs/rfcs/blob/master/text/0615-autotracking-memoization.md#detailed-design).
+This cache returns the most recent value of the helper, and will update whenever
+the helper updates. Users can access the value using the `getValue` function for
+caches.
+
+If the helper has a scheduled effect, using `getValue` on the cache will not run
+it eagerly. It will run as scheduled, until the helper is destroyed.
+
+The cache will be also be destroyable, so that using `destroy()` from the
+destroyables API on it will trigger its destruction early. Users can do this to
+clean up a helper before the parent context is destroyed.
+
+### Effect Helper Timing Semantics
+
+Standard helpers that return a value will only be updated when they are used,
+either in JavaScript or in the template. The args getter and the relevant helper
+manager lifecycle hooks will be called when the `value` property on the helper
+is used.
+
+Side-effecting helpers, by contrast, run their updates specifically when
+scheduled. When introduced by the Helper Manager RFC, there was no relative
+ordering specified in the scheduling of side-effecting helpers, because there
+was no way for them to have _children_, and we don't generally specify ordering
+of siblings. With this RFC, it will be possible to invoke a side-effecting
+helper within another side-effecting helper, so they will be able to have
+children for the first time.
+
+This RFC proposes modifying the Helper Manager RFC to specify that the
+`runEffect` hook of a helper always runs _after_ the `runEffect` hooks of its
+children. This mirrors the timing semantics of modifier hooks in templates.
+
+### Ergonomics
+
+This is a low-level API for invoking helpers and creating instances. The API is
+meant to be functional, but not particularly readable or ergonomic. This API can
+be wrapped with higher level, more ergonomic APIs in the ecosystem, until we're
+sure what the final API should be.
+
+## How we teach this
+
+This API is meant to be a low-level primitive which will eventually be replaced
+with higher level wrappers, possibly decorators, that will be much easier to use
+and recommend to average app developers. As such, it will only be taught through
+API documentation.
+
+Once community addons are built with higher level APIs that are more ergonomic,
+we should also add a section in the guides that uses them to demonstrate
+techniques for using helpers in JS. This strategy is similar to how modifiers
+are documented today.
+
+### API Docs
+
+#### `invokeHelper`
+
+The `invokeHelper` function can be used to create a helper instance in
+JavaScript.
+
+```js
+// app/components/data-loader.js
+import Component from '@glimmer/component';
+import Helper from '@ember/component/helper';
+import { invokeHelper } from '@ember/helper';
+
+class PlusOne extends Helper {
+ compute([num]) {
+ return number + 1;
+ }
+}
+
+export default class PlusOne extends Component {
+ plusOne = invokeHelper(this, RemoteData, () => {
+ return {
+ positional: [this.args.number],
+ };
+ });
+}
+```
+```hbs
+{{this.plusOne.value}}
+```
+
+It receives three arguments:
+
+* `context`: The parent context of the helper. When the parent is torn down and
+ removed, the helper will be as well.
+* `definition`: The definition of the helper.
+* `computeArgs`: An optional function that produces the arguments to the helper.
+ The function receives the parent context as an argument, and must return an
+ object with a `positional` property that is an array and/or a `named`
+ property that is an object.
+
+And it returns a Cache instance that contains the most recent value of the
+helper. You can access the helper using `getValue()` like any other cache. The
+cache is also destroyable, and using the `destroy()` function on it will cause
+the helper to be torn down.
+
+Note that using `getValue()` on helpers that have scheduled effects will not
+trigger the effect early. Effects will continue to run at their scheduled time.
+
+## Drawbacks
+
+- Additional API surface complexity. There will be additional ways to use
+ helpers that we will have to teach users about in general. This is true, but
+ given it helps to solve a lot of common problems that users have in Octane it
+ should be worthwhile.
+
+- This API is a primitive that is not particularly ergonomic or user friendly,
+ but this is part of the point. It gets the job done, and can be built on top
+ of to create a better high level API.
+
+## Alternatives
+
+- The [`@use` and Resources RFC](https://github.com/emberjs/rfcs/pull/567)
+ proposes a higher level approach to this problem space, but had a number of
+ concerns and drawbacks. After much discussion, we decided that it would be
+ better to ship the primitives to build something like it in user-space, and
+ prove out the ideas in it.